specweave 0.27.0 → 0.28.1

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 (85) hide show
  1. package/README.md +243 -97
  2. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts +6 -2
  3. package/dist/plugins/specweave-github/lib/github-client-v2.d.ts.map +1 -1
  4. package/dist/plugins/specweave-github/lib/github-client-v2.js +28 -8
  5. package/dist/plugins/specweave-github/lib/github-client-v2.js.map +1 -1
  6. package/dist/plugins/specweave-github/lib/github-feature-sync-cli.d.ts +21 -0
  7. package/dist/plugins/specweave-github/lib/github-feature-sync-cli.d.ts.map +1 -0
  8. package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js +166 -0
  9. package/dist/plugins/specweave-github/lib/github-feature-sync-cli.js.map +1 -0
  10. package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts +5 -1
  11. package/dist/src/core/repo-structure/repo-bulk-discovery.d.ts.map +1 -1
  12. package/dist/src/core/repo-structure/repo-bulk-discovery.js +5 -3
  13. package/dist/src/core/repo-structure/repo-bulk-discovery.js.map +1 -1
  14. package/dist/src/core/repo-structure/repo-structure-manager.d.ts +1 -1
  15. package/dist/src/core/repo-structure/repo-structure-manager.d.ts.map +1 -1
  16. package/dist/src/core/repo-structure/repo-structure-manager.js +15 -16
  17. package/dist/src/core/repo-structure/repo-structure-manager.js.map +1 -1
  18. package/dist/src/core/sync/label-detector.d.ts.map +1 -1
  19. package/dist/src/core/sync/label-detector.js +22 -9
  20. package/dist/src/core/sync/label-detector.js.map +1 -1
  21. package/dist/src/metrics/calculators/deployment-frequency.d.ts +12 -8
  22. package/dist/src/metrics/calculators/deployment-frequency.d.ts.map +1 -1
  23. package/dist/src/metrics/calculators/deployment-frequency.js +16 -12
  24. package/dist/src/metrics/calculators/deployment-frequency.js.map +1 -1
  25. package/dist/src/metrics/dora-calculator.d.ts +2 -1
  26. package/dist/src/metrics/dora-calculator.d.ts.map +1 -1
  27. package/dist/src/metrics/dora-calculator.js +9 -4
  28. package/dist/src/metrics/dora-calculator.js.map +1 -1
  29. package/dist/src/metrics/github-client.d.ts +12 -0
  30. package/dist/src/metrics/github-client.d.ts.map +1 -1
  31. package/dist/src/metrics/github-client.js +30 -0
  32. package/dist/src/metrics/github-client.js.map +1 -1
  33. package/dist/src/sync/sync-coordinator.d.ts +33 -0
  34. package/dist/src/sync/sync-coordinator.d.ts.map +1 -1
  35. package/dist/src/sync/sync-coordinator.js +203 -2
  36. package/dist/src/sync/sync-coordinator.js.map +1 -1
  37. package/dist/src/utils/env-file-generator.d.ts +8 -23
  38. package/dist/src/utils/env-file-generator.d.ts.map +1 -1
  39. package/dist/src/utils/env-file-generator.js +31 -71
  40. package/dist/src/utils/env-file-generator.js.map +1 -1
  41. package/package.json +7 -2
  42. package/plugins/specweave/agents/architect/AGENT.md +2 -2
  43. package/plugins/specweave/agents/docs-writer/AGENT.md +2 -2
  44. package/plugins/specweave/agents/pm/AGENT.md +2 -2
  45. package/plugins/specweave/agents/qa-lead/AGENT.md +2 -2
  46. package/plugins/specweave/agents/security/AGENT.md +2 -2
  47. package/plugins/specweave/agents/tdd-orchestrator/AGENT.md +2 -2
  48. package/plugins/specweave/agents/tech-lead/AGENT.md +2 -2
  49. package/plugins/specweave/agents/test-aware-planner/AGENT.md +2 -2
  50. package/plugins/specweave/hooks/post-edit-write-consolidated.sh +87 -0
  51. package/plugins/specweave/hooks/post-increment-completion.sh +84 -0
  52. package/plugins/specweave/hooks/post-increment-planning.sh +114 -7
  53. package/plugins/specweave/lib/hooks/sync-increment-closure.js +66 -0
  54. package/plugins/specweave/lib/hooks/sync-increment-closure.ts +111 -0
  55. package/plugins/specweave-ado/lib/ado-multi-project-sync.js +0 -1
  56. package/plugins/specweave-github/lib/github-client-v2.js +32 -8
  57. package/plugins/specweave-github/lib/github-client-v2.ts +31 -9
  58. package/plugins/specweave-github/lib/github-feature-sync-cli.js +135 -0
  59. package/plugins/specweave-github/lib/github-feature-sync-cli.ts +194 -0
  60. package/plugins/specweave-github/skills/github-issue-standard/SKILL.md +43 -0
  61. package/plugins/specweave-infrastructure/agents/devops/AGENT.md +2 -2
  62. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +3 -3
  63. package/src/templates/.env.example +9 -26
  64. package/plugins/specweave/hooks/docs-changed.sh.backup +0 -79
  65. package/plugins/specweave/hooks/human-input-required.sh.backup +0 -75
  66. package/plugins/specweave/hooks/post-first-increment.sh.backup +0 -61
  67. package/plugins/specweave/hooks/post-increment-change.sh.backup +0 -98
  68. package/plugins/specweave/hooks/post-increment-completion.sh.backup +0 -231
  69. package/plugins/specweave/hooks/post-increment-planning.sh.backup +0 -1048
  70. package/plugins/specweave/hooks/post-increment-status-change.sh.backup +0 -147
  71. package/plugins/specweave/hooks/post-spec-update.sh.backup +0 -158
  72. package/plugins/specweave/hooks/post-user-story-complete.sh.backup +0 -179
  73. package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +0 -83
  74. package/plugins/specweave/hooks/pre-implementation.sh.backup +0 -67
  75. package/plugins/specweave/hooks/pre-task-completion.sh.backup +0 -194
  76. package/plugins/specweave/hooks/pre-tool-use.sh.backup +0 -133
  77. package/plugins/specweave/hooks/user-prompt-submit.sh.backup +0 -386
  78. package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +0 -353
  79. package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +0 -172
  80. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +0 -170
  81. package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +0 -1104
  82. package/plugins/specweave-github/hooks/post-task-completion.sh.backup +0 -258
  83. package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +0 -172
  84. package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +0 -1017
  85. package/plugins/specweave-release/hooks/post-task-completion.sh.backup +0 -110
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, readFileSync } from "fs";
3
+ import * as path from "path";
4
+ import { GitHubFeatureSync } from "./github-feature-sync.js";
5
+ import { GitHubClientV2 } from "./github-client-v2.js";
6
+ async function loadGitHubConfig() {
7
+ const projectRoot = process.cwd();
8
+ const configPath = path.join(projectRoot, ".specweave/config.json");
9
+ let owner = process.env.GITHUB_OWNER || "";
10
+ let repo = process.env.GITHUB_REPO || "";
11
+ const token = process.env.GITHUB_TOKEN || "";
12
+ if (existsSync(configPath)) {
13
+ try {
14
+ const config = JSON.parse(readFileSync(configPath, "utf-8"));
15
+ if (config.sync?.github?.owner && config.sync?.github?.repo) {
16
+ owner = config.sync.github.owner;
17
+ repo = config.sync.github.repo;
18
+ } else if (config.multiProject?.enabled && config.multiProject?.activeProject) {
19
+ const activeProject = config.multiProject.activeProject;
20
+ const projectConfig = config.multiProject.projects?.[activeProject];
21
+ if (projectConfig?.externalTools?.github?.repository) {
22
+ const parts = projectConfig.externalTools.github.repository.split("/");
23
+ if (parts.length === 2) {
24
+ owner = parts[0];
25
+ repo = parts[1];
26
+ }
27
+ }
28
+ } else if (config.sync?.activeProfile && config.sync?.profiles) {
29
+ const profile = config.sync.profiles[config.sync.activeProfile];
30
+ if (profile?.config?.owner && profile?.config?.repo) {
31
+ owner = profile.config.owner;
32
+ repo = profile.config.repo;
33
+ }
34
+ }
35
+ } catch (error) {
36
+ console.error("\u26A0\uFE0F Failed to parse config.json:", error);
37
+ }
38
+ }
39
+ if (!owner || !repo) {
40
+ try {
41
+ const { execSync } = await import("child_process");
42
+ const remoteUrl = execSync("git remote get-url origin 2>/dev/null", {
43
+ encoding: "utf-8",
44
+ cwd: projectRoot
45
+ }).trim();
46
+ const match = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
47
+ if (match) {
48
+ owner = owner || match[1];
49
+ repo = repo || match[2];
50
+ }
51
+ } catch {
52
+ }
53
+ }
54
+ if (!token) {
55
+ console.error("\u274C GITHUB_TOKEN not set");
56
+ console.error(" Set it in .env file or export GITHUB_TOKEN=ghp_xxx");
57
+ return null;
58
+ }
59
+ if (!owner || !repo) {
60
+ console.error("\u274C Could not detect GitHub owner/repo");
61
+ console.error(" Set sync.github.owner and sync.github.repo in .specweave/config.json");
62
+ return null;
63
+ }
64
+ return { owner, repo, token };
65
+ }
66
+ async function main() {
67
+ const args = process.argv.slice(2);
68
+ if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
69
+ console.log("Usage: node github-feature-sync-cli.js <feature-id>");
70
+ console.log("");
71
+ console.log("Arguments:");
72
+ console.log(" feature-id Feature ID (e.g., FS-062)");
73
+ console.log("");
74
+ console.log("Environment:");
75
+ console.log(" GITHUB_TOKEN Required - GitHub personal access token");
76
+ console.log("");
77
+ console.log("Example:");
78
+ console.log(" GITHUB_TOKEN=ghp_xxx node github-feature-sync-cli.js FS-062");
79
+ process.exit(args.length === 0 ? 1 : 0);
80
+ }
81
+ const featureId = args[0];
82
+ if (!featureId.match(/^FS-\d+$/i)) {
83
+ console.error(`\u274C Invalid feature ID: ${featureId}`);
84
+ console.error(" Expected format: FS-XXX (e.g., FS-062)");
85
+ process.exit(1);
86
+ }
87
+ console.log(`
88
+ \u{1F419} GitHub Feature Sync CLI`);
89
+ console.log(` Feature: ${featureId}`);
90
+ const config = await loadGitHubConfig();
91
+ if (!config) {
92
+ process.exit(1);
93
+ }
94
+ console.log(` Repository: ${config.owner}/${config.repo}`);
95
+ const projectRoot = process.cwd();
96
+ const specsDir = path.join(projectRoot, ".specweave/docs/internal/specs");
97
+ const profile = {
98
+ provider: "github",
99
+ displayName: "GitHub",
100
+ config: {
101
+ owner: config.owner,
102
+ repo: config.repo,
103
+ token: config.token
104
+ },
105
+ timeRange: {
106
+ default: "1M",
107
+ max: "3M"
108
+ }
109
+ };
110
+ const client = new GitHubClientV2(profile);
111
+ const sync = new GitHubFeatureSync(client, specsDir, projectRoot);
112
+ try {
113
+ console.log(`
114
+ \u{1F504} Syncing ${featureId} to GitHub...`);
115
+ const result = await sync.syncFeatureToGitHub(featureId);
116
+ console.log(`
117
+ \u2705 Sync complete!`);
118
+ console.log(` \u{1F3AF} Milestone: #${result.milestoneNumber}`);
119
+ console.log(` \u{1F4DD} Issues created: ${result.issuesCreated}`);
120
+ console.log(` \u{1F504} Issues updated: ${result.issuesUpdated}`);
121
+ console.log(` \u{1F4DA} User stories processed: ${result.userStoriesProcessed}`);
122
+ if (result.milestoneUrl) {
123
+ console.log(` \u{1F517} ${result.milestoneUrl}`);
124
+ }
125
+ process.exit(0);
126
+ } catch (error) {
127
+ console.error(`
128
+ \u274C Sync failed:`, error);
129
+ process.exit(1);
130
+ }
131
+ }
132
+ main().catch((error) => {
133
+ console.error("Fatal error:", error);
134
+ process.exit(1);
135
+ });
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * GitHub Feature Sync CLI
4
+ *
5
+ * CLI wrapper for GitHubFeatureSync.syncFeatureToGitHub()
6
+ * Called by post-increment-planning.sh hook to create GitHub issues
7
+ * after increment creation.
8
+ *
9
+ * Usage:
10
+ * node github-feature-sync-cli.js <feature-id>
11
+ * node github-feature-sync-cli.js FS-062
12
+ *
13
+ * Environment:
14
+ * GITHUB_TOKEN - Required
15
+ * GITHUB_OWNER - Optional (detected from config.json or git remote)
16
+ * GITHUB_REPO - Optional (detected from config.json or git remote)
17
+ *
18
+ * @see ADR-0139 (Unified Post-Increment Sync)
19
+ */
20
+
21
+ import { existsSync, readFileSync } from 'fs';
22
+ import * as path from 'path';
23
+ import { GitHubFeatureSync } from './github-feature-sync.js';
24
+ import { GitHubClientV2 } from './github-client-v2.js';
25
+
26
+ interface GitHubConfig {
27
+ owner: string;
28
+ repo: string;
29
+ token: string;
30
+ }
31
+
32
+ async function loadGitHubConfig(): Promise<GitHubConfig | null> {
33
+ const projectRoot = process.cwd();
34
+ const configPath = path.join(projectRoot, '.specweave/config.json');
35
+
36
+ let owner = process.env.GITHUB_OWNER || '';
37
+ let repo = process.env.GITHUB_REPO || '';
38
+ const token = process.env.GITHUB_TOKEN || '';
39
+
40
+ // Try to load from config.json
41
+ if (existsSync(configPath)) {
42
+ try {
43
+ const config = JSON.parse(readFileSync(configPath, 'utf-8'));
44
+
45
+ // Method 1: sync.github
46
+ if (config.sync?.github?.owner && config.sync?.github?.repo) {
47
+ owner = config.sync.github.owner;
48
+ repo = config.sync.github.repo;
49
+ }
50
+ // Method 2: multiProject.projects[activeProject].externalTools.github
51
+ else if (config.multiProject?.enabled && config.multiProject?.activeProject) {
52
+ const activeProject = config.multiProject.activeProject;
53
+ const projectConfig = config.multiProject.projects?.[activeProject];
54
+ if (projectConfig?.externalTools?.github?.repository) {
55
+ const parts = projectConfig.externalTools.github.repository.split('/');
56
+ if (parts.length === 2) {
57
+ owner = parts[0];
58
+ repo = parts[1];
59
+ }
60
+ }
61
+ }
62
+ // Method 3: sync.profiles[activeProfile]
63
+ else if (config.sync?.activeProfile && config.sync?.profiles) {
64
+ const profile = config.sync.profiles[config.sync.activeProfile];
65
+ if (profile?.config?.owner && profile?.config?.repo) {
66
+ owner = profile.config.owner;
67
+ repo = profile.config.repo;
68
+ }
69
+ }
70
+ } catch (error) {
71
+ console.error('⚠️ Failed to parse config.json:', error);
72
+ }
73
+ }
74
+
75
+ // Fallback: detect from git remote
76
+ if (!owner || !repo) {
77
+ try {
78
+ const { execSync } = await import('child_process');
79
+ const remoteUrl = execSync('git remote get-url origin 2>/dev/null', {
80
+ encoding: 'utf-8',
81
+ cwd: projectRoot
82
+ }).trim();
83
+
84
+ // Parse GitHub URL (HTTPS or SSH)
85
+ const match = remoteUrl.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
86
+ if (match) {
87
+ owner = owner || match[1];
88
+ repo = repo || match[2];
89
+ }
90
+ } catch {
91
+ // Git detection failed, continue with what we have
92
+ }
93
+ }
94
+
95
+ if (!token) {
96
+ console.error('❌ GITHUB_TOKEN not set');
97
+ console.error(' Set it in .env file or export GITHUB_TOKEN=ghp_xxx');
98
+ return null;
99
+ }
100
+
101
+ if (!owner || !repo) {
102
+ console.error('❌ Could not detect GitHub owner/repo');
103
+ console.error(' Set sync.github.owner and sync.github.repo in .specweave/config.json');
104
+ return null;
105
+ }
106
+
107
+ return { owner, repo, token };
108
+ }
109
+
110
+ async function main() {
111
+ const args = process.argv.slice(2);
112
+
113
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
114
+ console.log('Usage: node github-feature-sync-cli.js <feature-id>');
115
+ console.log('');
116
+ console.log('Arguments:');
117
+ console.log(' feature-id Feature ID (e.g., FS-062)');
118
+ console.log('');
119
+ console.log('Environment:');
120
+ console.log(' GITHUB_TOKEN Required - GitHub personal access token');
121
+ console.log('');
122
+ console.log('Example:');
123
+ console.log(' GITHUB_TOKEN=ghp_xxx node github-feature-sync-cli.js FS-062');
124
+ process.exit(args.length === 0 ? 1 : 0);
125
+ }
126
+
127
+ const featureId = args[0];
128
+
129
+ // Validate feature ID format
130
+ if (!featureId.match(/^FS-\d+$/i)) {
131
+ console.error(`❌ Invalid feature ID: ${featureId}`);
132
+ console.error(' Expected format: FS-XXX (e.g., FS-062)');
133
+ process.exit(1);
134
+ }
135
+
136
+ console.log(`\n🐙 GitHub Feature Sync CLI`);
137
+ console.log(` Feature: ${featureId}`);
138
+
139
+ // Load config
140
+ const config = await loadGitHubConfig();
141
+ if (!config) {
142
+ process.exit(1);
143
+ }
144
+
145
+ console.log(` Repository: ${config.owner}/${config.repo}`);
146
+
147
+ // Create client and sync
148
+ const projectRoot = process.cwd();
149
+ const specsDir = path.join(projectRoot, '.specweave/docs/internal/specs');
150
+
151
+ const profile = {
152
+ provider: 'github' as const,
153
+ displayName: 'GitHub',
154
+ config: {
155
+ owner: config.owner,
156
+ repo: config.repo,
157
+ token: config.token
158
+ },
159
+ timeRange: {
160
+ default: '1M' as const,
161
+ max: '3M' as const
162
+ }
163
+ };
164
+
165
+ const client = new GitHubClientV2(profile);
166
+ const sync = new GitHubFeatureSync(client, specsDir, projectRoot);
167
+
168
+ try {
169
+ console.log(`\n🔄 Syncing ${featureId} to GitHub...`);
170
+
171
+ const result = await sync.syncFeatureToGitHub(featureId);
172
+
173
+ console.log(`\n✅ Sync complete!`);
174
+ console.log(` 🎯 Milestone: #${result.milestoneNumber}`);
175
+ console.log(` 📝 Issues created: ${result.issuesCreated}`);
176
+ console.log(` 🔄 Issues updated: ${result.issuesUpdated}`);
177
+ console.log(` 📚 User stories processed: ${result.userStoriesProcessed}`);
178
+
179
+ if (result.milestoneUrl) {
180
+ console.log(` 🔗 ${result.milestoneUrl}`);
181
+ }
182
+
183
+ process.exit(0);
184
+ } catch (error) {
185
+ console.error(`\n❌ Sync failed:`, error);
186
+ process.exit(1);
187
+ }
188
+ }
189
+
190
+ // Run CLI
191
+ main().catch(error => {
192
+ console.error('Fatal error:', error);
193
+ process.exit(1);
194
+ });
@@ -11,6 +11,49 @@ description: Standard format for ALL GitHub issues created by SpecWeave. Ensures
11
11
  - Increments (0001-* folders)
12
12
  - Specs (spec-*.md files)
13
13
 
14
+ ## Issue Title Format (MANDATORY)
15
+
16
+ ### ✅ ONLY Allowed Title Formats
17
+
18
+ ```
19
+ [FS-XXX][US-YYY] User Story Title ← STANDARD (User Stories)
20
+ [FS-XXX] Feature Title ← Rare (Feature-level only)
21
+ ```
22
+
23
+ **Examples**:
24
+ - ✅ `[FS-059][US-003] Hook Optimization (P0)`
25
+ - ✅ `[FS-054][US-001] Fix Reopen Desync Bug (P0)`
26
+ - ✅ `[FS-048] Smart Pagination Feature`
27
+
28
+ ### ❌ PROHIBITED Title Formats (NEVER USE)
29
+
30
+ ```
31
+ [BUG] Title ← WRONG! Bug is a LABEL, not title prefix
32
+ [HOTFIX] Title ← WRONG! Hotfix is a LABEL
33
+ [FEATURE] Title ← WRONG! Feature is a LABEL
34
+ [DOCS] Title ← WRONG! Docs is a LABEL
35
+ [Increment XXXX] Title ← DEPRECATED! Old format
36
+ ```
37
+
38
+ **Why?** Type-based prefixes like `[BUG]` break traceability:
39
+ - Cannot link to Feature Spec (FS-XXX)
40
+ - Cannot link to User Story (US-YYY)
41
+ - Violates SpecWeave's data flow: `Increment → Living Docs → GitHub`
42
+
43
+ **What to do instead?**
44
+ 1. Link work to a Feature (FS-XXX) in living docs
45
+ 2. Create User Story (US-YYY) under that feature
46
+ 3. Use GitHub **labels** for categorization: `bug`, `enhancement`, `hotfix`
47
+
48
+ ### Validation
49
+
50
+ The GitHub client (`github-client-v2.ts`) enforces this:
51
+ - Rejects titles starting with `[BUG]`, `[HOTFIX]`, `[FEATURE]`, etc.
52
+ - Rejects deprecated `[Increment XXXX]` format
53
+ - Only allows `[FS-XXX][US-YYY]` or `[FS-XXX]` formats
54
+
55
+ ---
56
+
14
57
  ## The Standard Format
15
58
 
16
59
  ### ✅ Required Elements
@@ -2,8 +2,8 @@
2
2
  name: devops
3
3
  description: DevOps and infrastructure expert that generates IaC ONE COMPONENT AT A TIME (VPC → Compute → Database → Monitoring) to prevent crashes. Handles Terraform, Kubernetes, Docker, CI/CD. **CRITICAL CHUNKING RULE - Large deployments (EKS + RDS + monitoring = 20+ files) done incrementally.** Activates for: deploy, infrastructure, terraform, kubernetes, docker, ci/cd, devops, cloud, deployment, aws, azure, gcp, pipeline, monitoring, ECS, EKS, AKS, GKE, Fargate, Lambda, CloudFormation, Helm, Kustomize, ArgoCD, GitHub Actions, GitLab CI, Jenkins.
4
4
  tools: Read, Write, Edit, Bash
5
- model: claude-sonnet-4-5-20250929
6
- model_preference: haiku
5
+ model: claude-opus-4-5-20251101
6
+ model_preference: opus
7
7
  cost_profile: execution
8
8
  fallback_behavior: flexible
9
9
  max_response_tokens: 2000
@@ -1,6 +1,6 @@
1
- import { EnhancedContentBuilder } from "../../../dist/src/core/sync/enhanced-content-builder.js";
2
- import { SpecIncrementMapper } from "../../../dist/src/core/sync/spec-increment-mapper.js";
3
- import { parseSpecContent } from "../../../dist/src/core/spec-content-sync.js";
1
+ import { EnhancedContentBuilder } from "../../../src/core/sync/enhanced-content-builder.js";
2
+ import { SpecIncrementMapper } from "../../../src/core/sync/spec-increment-mapper.js";
3
+ import { parseSpecContent } from "../../../src/core/spec-content-sync.js";
4
4
  import * as path from "path";
5
5
  import * as fs from "fs/promises";
6
6
  async function syncSpecToJiraWithEnhancedContent(options) {
@@ -53,35 +53,18 @@ VERCEL_TOKEN=your-vercel-token-here
53
53
  # ============================================================================
54
54
 
55
55
  # ----------------------------------------------------------------------------
56
- # GitHub - 3 Strategies for Team Organization
56
+ # GitHub
57
57
  # ----------------------------------------------------------------------------
58
+ # RECOMMENDED: Use gh CLI instead of tokens
59
+ # gh auth login
60
+ #
61
+ # Only use GITHUB_TOKEN if gh CLI is not available (e.g., CI/CD)
58
62
  # Guide: https://github.com/settings/tokens
59
- # Scopes: repo, read:org, workflow
63
+ # Scopes: repo, read:org
60
64
 
61
- # Required for all strategies:
62
- GH_TOKEN=ghp_your-github-token-40-chars
63
-
64
- # Strategy 1: Repository-per-team (MOST COMMON)
65
- # Use when: Each team has separate repositories (microservices, multi-repo)
66
- # Example: Frontend team → frontend-app, Backend team → backend-api
67
- GITHUB_STRATEGY=repository-per-team
68
- GITHUB_OWNER=myorg
69
- GITHUB_REPOS=frontend-app,backend-api,mobile-app,qa-tools
70
-
71
- # Strategy 2: Team-based (MONOREPO)
72
- # Use when: Single repository with team-based filtering
73
- # Example: Monorepo with teams working on different parts
74
- # GITHUB_STRATEGY=team-based
75
- # GITHUB_OWNER=myorg
76
- # GITHUB_REPO=main-product
77
- # GITHUB_TEAMS=frontend-team,backend-team,mobile-team,qa-team
78
-
79
- # Strategy 3: Team-multi-repo (COMPLEX)
80
- # Use when: Teams own multiple repositories (platform teams)
81
- # Example: Platform team owns api-gateway + auth-service
82
- # GITHUB_STRATEGY=team-multi-repo
83
- # GITHUB_OWNER=myorg
84
- # GITHUB_TEAM_REPO_MAPPING='{"platform-team":["api-gateway","auth-service"],"frontend-team":["web-app","mobile-app"]}'
65
+ GITHUB_TOKEN=ghp_your-github-token-40-chars
66
+
67
+ # All other GitHub configuration is in .specweave/config.json
85
68
 
86
69
  # ----------------------------------------------------------------------------
87
70
  # Jira - 3 Strategies for Team Organization
@@ -1,79 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave Docs-Changed Hook
4
- # Runs after file changes are detected
5
- # Detects if documentation was changed during implementation
6
- # Triggers review workflow if needed
7
-
8
- set -e
9
-
10
- # Find project root by searching upward for .specweave/ directory
11
- # Works regardless of where hook is installed (source or .claude/hooks/)
12
- find_project_root() {
13
- local dir="$1"
14
- while [ "$dir" != "/" ]; do
15
- if [ -d "$dir/.specweave" ]; then
16
- echo "$dir"
17
- return 0
18
- fi
19
- dir="$(dirname "$dir")"
20
- done
21
- # Fallback: try current directory
22
- if [ -d "$(pwd)/.specweave" ]; then
23
- pwd
24
- else
25
- echo "$(pwd)"
26
- fi
27
- }
28
-
29
- PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
30
- cd "$PROJECT_ROOT"
31
-
32
- # Colors
33
- RED='\033[0;31m'
34
- YELLOW='\033[1;33m'
35
- NC='\033[0m'
36
-
37
- # Get changed files (git)
38
- if ! git rev-parse --git-dir > /dev/null 2>&1; then
39
- # Not a git repository, skip
40
- exit 0
41
- fi
42
-
43
- CHANGED_FILES=$(git diff --name-only HEAD 2>/dev/null || echo "")
44
-
45
- if [ -z "$CHANGED_FILES" ]; then
46
- # No changes
47
- exit 0
48
- fi
49
-
50
- # Check if any documentation files changed
51
- DOC_CHANGES=$(echo "$CHANGED_FILES" | grep -E '\.specweave/(docs|increments/.*/.*\.md)' || true)
52
-
53
- if [ -n "$DOC_CHANGES" ]; then
54
- echo -e "${RED}⚠️ Documentation changed during implementation${NC}"
55
- echo ""
56
- echo "📋 Files changed:"
57
- echo "$DOC_CHANGES" | sed 's/^/ /'
58
- echo ""
59
- echo -e "${YELLOW}🔔 Recommended actions:${NC}"
60
- echo " 1. Review documentation changes"
61
- echo " 2. Update tasks.md if architecture changed"
62
- echo " 3. Type /review-docs to see full impact"
63
- echo ""
64
-
65
- # Play notification sound
66
- case "$(uname -s)" in
67
- Darwin)
68
- afplay /System/Library/Sounds/Ping.aiff 2>/dev/null &
69
- ;;
70
- Linux)
71
- paplay /usr/share/sounds/freedesktop/stereo/dialog-warning.oga 2>/dev/null || true
72
- ;;
73
- esac
74
-
75
- # Log to hooks log
76
- LOGS_DIR=".specweave/logs"
77
- mkdir -p "$LOGS_DIR"
78
- echo "[$(date)] Documentation changed: $DOC_CHANGES" >> "$LOGS_DIR/hooks.log"
79
- fi
@@ -1,75 +0,0 @@
1
- #!/bin/bash
2
-
3
- # SpecWeave Human-Input-Required Hook
4
- # Runs when Claude needs clarification or approval
5
- #
6
- # Actions:
7
- # 1. Play notification sound (Ping.aiff)
8
- # 2. Log the question/requirement
9
- # 3. Record in current increment's work log (if applicable)
10
-
11
- set -e
12
-
13
- # Find project root by searching upward for .specweave/ directory
14
- # Works regardless of where hook is installed (source or .claude/hooks/)
15
- find_project_root() {
16
- local dir="$1"
17
- while [ "$dir" != "/" ]; do
18
- if [ -d "$dir/.specweave" ]; then
19
- echo "$dir"
20
- return 0
21
- fi
22
- dir="$(dirname "$dir")"
23
- done
24
- # Fallback: try current directory
25
- if [ -d "$(pwd)/.specweave" ]; then
26
- pwd
27
- else
28
- echo "$(pwd)"
29
- fi
30
- }
31
-
32
- PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
33
- cd "$PROJECT_ROOT"
34
-
35
- # Get question/requirement (passed as argument or default)
36
- QUESTION="${1:-User input required}"
37
-
38
- echo "❓ Human input required"
39
-
40
- # 1. Play notification sound (cross-platform)
41
- play_sound() {
42
- case "$(uname -s)" in
43
- Darwin)
44
- afplay /System/Library/Sounds/Ping.aiff 2>/dev/null &
45
- ;;
46
- Linux)
47
- paplay /usr/share/sounds/freedesktop/stereo/dialog-question.oga 2>/dev/null || \
48
- aplay /usr/share/sounds/alsa/Side_Left.wav 2>/dev/null || true
49
- ;;
50
- MINGW*|MSYS*|CYGWIN*)
51
- powershell -c "(New-Object Media.SoundPlayer 'C:\Windows\Media\notify.wav').PlaySync();" 2>/dev/null || true
52
- ;;
53
- esac
54
- }
55
-
56
- play_sound &
57
-
58
- # 2. Log to main hooks log
59
- LOGS_DIR=".specweave/logs"
60
- mkdir -p "$LOGS_DIR"
61
- echo "[$(date)] Human input required: $QUESTION" >> "$LOGS_DIR/hooks.log"
62
-
63
- # 3. Log to current work context (if exists)
64
- CURRENT_WORK=$(find .specweave/work -maxdepth 1 -type d -name "current-*" | head -1 || true)
65
-
66
- if [ -n "$CURRENT_WORK" ] && [ -d "$CURRENT_WORK" ]; then
67
- echo "" >> "$CURRENT_WORK/notes.md"
68
- echo "## Input Required ($(date +%Y-%m-%d\ %H:%M))" >> "$CURRENT_WORK/notes.md"
69
- echo "" >> "$CURRENT_WORK/notes.md"
70
- echo "$QUESTION" >> "$CURRENT_WORK/notes.md"
71
- echo "" >> "$CURRENT_WORK/notes.md"
72
- echo "📝 Logged to $CURRENT_WORK/notes.md"
73
- fi
74
-
75
- echo "✅ Hook complete"
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env bash
2
- # SpecWeave Post-First-Increment Hook
3
- #
4
- # Triggers after the first increment is completed
5
- # Congratulates the user on completing their first increment
6
- #
7
- # NON-INTERACTIVE: Just shows a message (hooks run in background)
8
-
9
- set -euo pipefail
10
-
11
- # Get project root (where .specweave/ lives)
12
- PROJECT_ROOT="$(pwd)"
13
-
14
- # Check if .specweave directory exists
15
- if [ ! -d ".specweave" ]; then
16
- # Not in SpecWeave project, skip
17
- exit 0
18
- fi
19
-
20
- # Check if this is the first increment completion
21
- # Count completed increments in .specweave/increments/
22
- COMPLETED_COUNT=0
23
- if [ -d ".specweave/increments" ]; then
24
- # Count directories that have COMPLETION-REPORT.md or completion metadata
25
- for inc_dir in .specweave/increments/[0-9][0-9][0-9][0-9]-*/; do
26
- if [ -d "$inc_dir" ]; then
27
- if [ -f "${inc_dir}reports/COMPLETION-REPORT.md" ] || \
28
- [ -f "${inc_dir}COMPLETION-SUMMARY.md" ] || \
29
- ([ -f "${inc_dir}metadata.json" ] && grep -q '"status".*"completed"' "${inc_dir}metadata.json" 2>/dev/null); then
30
- COMPLETED_COUNT=$((COMPLETED_COUNT + 1))
31
- fi
32
- fi
33
- done
34
- fi
35
-
36
- # Only trigger on first completion
37
- if [ "$COMPLETED_COUNT" -ne 1 ]; then
38
- exit 0
39
- fi
40
-
41
- # Show congratulations message (non-interactive)
42
- echo ""
43
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
44
- echo "🎉 Congratulations! You completed your first increment!"
45
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
46
- echo ""
47
- echo "✅ Your increment has been documented in:"
48
- echo " .specweave/increments/[increment-id]/"
49
- echo ""
50
- echo "📚 View your documentation:"
51
- echo " - Specs: .specweave/docs/internal/specs/"
52
- echo " - Architecture: .specweave/docs/internal/architecture/"
53
- echo ""
54
- echo "🚀 Next steps:"
55
- echo " - Review your increment: /specweave:status"
56
- echo " - Start next increment: /specweave:increment \"feature name\""
57
- echo ""
58
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
59
- echo ""
60
-
61
- exit 0