specweave 1.0.235 → 1.0.239

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 (196) hide show
  1. package/README.md +89 -193
  2. package/dist/plugins/specweave-github/lib/github-ac-comment-poster.d.ts +37 -0
  3. package/dist/plugins/specweave-github/lib/github-ac-comment-poster.d.ts.map +1 -0
  4. package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js +176 -0
  5. package/dist/plugins/specweave-github/lib/github-ac-comment-poster.js.map +1 -0
  6. package/dist/plugins/specweave-github/lib/github-batch-sync.d.ts +36 -0
  7. package/dist/plugins/specweave-github/lib/github-batch-sync.d.ts.map +1 -0
  8. package/dist/plugins/specweave-github/lib/github-batch-sync.js +115 -0
  9. package/dist/plugins/specweave-github/lib/github-batch-sync.js.map +1 -0
  10. package/dist/plugins/specweave-github/lib/github-board-resolver-v2.d.ts +37 -0
  11. package/dist/plugins/specweave-github/lib/github-board-resolver-v2.d.ts.map +1 -0
  12. package/dist/plugins/specweave-github/lib/github-board-resolver-v2.js +56 -0
  13. package/dist/plugins/specweave-github/lib/github-board-resolver-v2.js.map +1 -0
  14. package/dist/plugins/specweave-github/lib/github-conflict-resolver.d.ts +68 -0
  15. package/dist/plugins/specweave-github/lib/github-conflict-resolver.d.ts.map +1 -0
  16. package/dist/plugins/specweave-github/lib/github-conflict-resolver.js +102 -0
  17. package/dist/plugins/specweave-github/lib/github-conflict-resolver.js.map +1 -0
  18. package/dist/plugins/specweave-github/lib/github-cross-repo-sync.d.ts +64 -0
  19. package/dist/plugins/specweave-github/lib/github-cross-repo-sync.d.ts.map +1 -0
  20. package/dist/plugins/specweave-github/lib/github-cross-repo-sync.js +162 -0
  21. package/dist/plugins/specweave-github/lib/github-cross-repo-sync.js.map +1 -0
  22. package/dist/plugins/specweave-github/lib/github-field-sync.d.ts +50 -0
  23. package/dist/plugins/specweave-github/lib/github-field-sync.d.ts.map +1 -0
  24. package/dist/plugins/specweave-github/lib/github-field-sync.js +107 -0
  25. package/dist/plugins/specweave-github/lib/github-field-sync.js.map +1 -0
  26. package/dist/plugins/specweave-github/lib/github-graphql-client.d.ts +53 -0
  27. package/dist/plugins/specweave-github/lib/github-graphql-client.d.ts.map +1 -0
  28. package/dist/plugins/specweave-github/lib/github-graphql-client.js +138 -0
  29. package/dist/plugins/specweave-github/lib/github-graphql-client.js.map +1 -0
  30. package/dist/plugins/specweave-github/lib/github-issue-body-generator.d.ts +40 -0
  31. package/dist/plugins/specweave-github/lib/github-issue-body-generator.d.ts.map +1 -0
  32. package/dist/plugins/specweave-github/lib/github-issue-body-generator.js +50 -0
  33. package/dist/plugins/specweave-github/lib/github-issue-body-generator.js.map +1 -0
  34. package/dist/plugins/specweave-github/lib/github-issue-body-parser.d.ts +30 -0
  35. package/dist/plugins/specweave-github/lib/github-issue-body-parser.d.ts.map +1 -0
  36. package/dist/plugins/specweave-github/lib/github-issue-body-parser.js +75 -0
  37. package/dist/plugins/specweave-github/lib/github-issue-body-parser.js.map +1 -0
  38. package/dist/plugins/specweave-github/lib/github-pull-sync.d.ts +94 -0
  39. package/dist/plugins/specweave-github/lib/github-pull-sync.d.ts.map +1 -0
  40. package/dist/plugins/specweave-github/lib/github-pull-sync.js +232 -0
  41. package/dist/plugins/specweave-github/lib/github-pull-sync.js.map +1 -0
  42. package/dist/plugins/specweave-github/lib/github-push-sync.d.ts +50 -0
  43. package/dist/plugins/specweave-github/lib/github-push-sync.d.ts.map +1 -0
  44. package/dist/plugins/specweave-github/lib/github-push-sync.js +114 -0
  45. package/dist/plugins/specweave-github/lib/github-push-sync.js.map +1 -0
  46. package/dist/plugins/specweave-github/lib/github-rate-limiter.d.ts +53 -0
  47. package/dist/plugins/specweave-github/lib/github-rate-limiter.d.ts.map +1 -0
  48. package/dist/plugins/specweave-github/lib/github-rate-limiter.js +109 -0
  49. package/dist/plugins/specweave-github/lib/github-rate-limiter.js.map +1 -0
  50. package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.d.ts +21 -0
  51. package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.d.ts.map +1 -0
  52. package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.js +161 -0
  53. package/dist/plugins/specweave-github/lib/github-spec-frontmatter-updater.js.map +1 -0
  54. package/dist/plugins/specweave-github/lib/github-sync-orchestrator.d.ts +46 -0
  55. package/dist/plugins/specweave-github/lib/github-sync-orchestrator.d.ts.map +1 -0
  56. package/dist/plugins/specweave-github/lib/github-sync-orchestrator.js +99 -0
  57. package/dist/plugins/specweave-github/lib/github-sync-orchestrator.js.map +1 -0
  58. package/dist/plugins/specweave-github/lib/github-us-auto-closer.d.ts +43 -0
  59. package/dist/plugins/specweave-github/lib/github-us-auto-closer.d.ts.map +1 -0
  60. package/dist/plugins/specweave-github/lib/github-us-auto-closer.js +153 -0
  61. package/dist/plugins/specweave-github/lib/github-us-auto-closer.js.map +1 -0
  62. package/dist/plugins/specweave-github/lib/index.d.ts +1 -4
  63. package/dist/plugins/specweave-github/lib/index.d.ts.map +1 -1
  64. package/dist/plugins/specweave-github/lib/index.js +1 -4
  65. package/dist/plugins/specweave-github/lib/index.js.map +1 -1
  66. package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.d.ts +7 -0
  67. package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.d.ts.map +1 -0
  68. package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.js +15 -0
  69. package/dist/plugins/specweave-testing/lib/playwright-ci-defaults.js.map +1 -0
  70. package/dist/plugins/specweave-testing/lib/playwright-cli-detector.d.ts +10 -0
  71. package/dist/plugins/specweave-testing/lib/playwright-cli-detector.d.ts.map +1 -0
  72. package/dist/plugins/specweave-testing/lib/playwright-cli-detector.js +36 -0
  73. package/dist/plugins/specweave-testing/lib/playwright-cli-detector.js.map +1 -0
  74. package/dist/plugins/specweave-testing/lib/playwright-cli-runner.d.ts +25 -0
  75. package/dist/plugins/specweave-testing/lib/playwright-cli-runner.d.ts.map +1 -0
  76. package/dist/plugins/specweave-testing/lib/playwright-cli-runner.js +57 -0
  77. package/dist/plugins/specweave-testing/lib/playwright-cli-runner.js.map +1 -0
  78. package/dist/plugins/specweave-testing/lib/playwright-routing.d.ts +7 -0
  79. package/dist/plugins/specweave-testing/lib/playwright-routing.d.ts.map +1 -0
  80. package/dist/plugins/specweave-testing/lib/playwright-routing.js +17 -0
  81. package/dist/plugins/specweave-testing/lib/playwright-routing.js.map +1 -0
  82. package/dist/src/cli/commands/auto.d.ts.map +1 -1
  83. package/dist/src/cli/commands/auto.js +1 -2
  84. package/dist/src/cli/commands/auto.js.map +1 -1
  85. package/dist/src/cli/commands/cancel-auto.js +1 -2
  86. package/dist/src/cli/commands/cancel-auto.js.map +1 -1
  87. package/dist/src/cli/commands/living-docs.js +2 -2
  88. package/dist/src/cli/commands/living-docs.js.map +1 -1
  89. package/dist/src/cli/commands/update.d.ts.map +1 -1
  90. package/dist/src/cli/commands/update.js +1 -2
  91. package/dist/src/cli/commands/update.js.map +1 -1
  92. package/dist/src/core/config/types.d.ts +8 -0
  93. package/dist/src/core/config/types.d.ts.map +1 -1
  94. package/dist/src/core/config/types.js +3 -0
  95. package/dist/src/core/config/types.js.map +1 -1
  96. package/dist/src/core/types/sync-profile.d.ts +72 -0
  97. package/dist/src/core/types/sync-profile.d.ts.map +1 -1
  98. package/dist/src/core/types/sync-profile.js +6 -0
  99. package/dist/src/core/types/sync-profile.js.map +1 -1
  100. package/package.json +2 -2
  101. package/plugins/specweave/hooks/hooks.json +2 -2
  102. package/plugins/specweave/hooks/startup-health-check.sh +1 -1
  103. package/plugins/specweave/hooks/stop-auto-v5.sh +166 -0
  104. package/plugins/specweave/hooks/user-prompt-submit.sh +10 -0
  105. package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +21 -1
  106. package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +1 -1
  107. package/plugins/specweave/skills/auto/SKILL.md +71 -251
  108. package/plugins/specweave/skills/team-build/SKILL.md +370 -0
  109. package/plugins/specweave/skills/team-merge/SKILL.md +123 -0
  110. package/plugins/specweave/skills/team-orchestrate/SKILL.md +800 -0
  111. package/plugins/specweave/skills/team-status/SKILL.md +89 -0
  112. package/plugins/specweave-github/MULTI-PROJECT-SYNC-ARCHITECTURE.md +94 -8
  113. package/plugins/specweave-github/commands/sync.md +17 -3
  114. package/plugins/specweave-github/hooks/github-ac-sync-handler.sh +255 -0
  115. package/plugins/specweave-github/hooks/github-auto-create-handler.sh +455 -0
  116. package/plugins/specweave-github/lib/github-ac-comment-poster.js +150 -0
  117. package/plugins/specweave-github/lib/github-ac-comment-poster.ts +245 -0
  118. package/plugins/specweave-github/lib/github-batch-sync.js +93 -0
  119. package/plugins/specweave-github/lib/github-batch-sync.ts +152 -0
  120. package/plugins/specweave-github/lib/github-board-resolver-v2.js +47 -0
  121. package/plugins/specweave-github/lib/github-board-resolver-v2.ts +73 -0
  122. package/plugins/specweave-github/lib/github-conflict-resolver.js +90 -0
  123. package/plugins/specweave-github/lib/github-conflict-resolver.ts +154 -0
  124. package/plugins/specweave-github/lib/github-cross-repo-sync.js +168 -0
  125. package/plugins/specweave-github/lib/github-cross-repo-sync.ts +252 -0
  126. package/plugins/specweave-github/lib/github-field-sync.js +116 -0
  127. package/plugins/specweave-github/lib/github-field-sync.ts +165 -0
  128. package/plugins/specweave-github/lib/github-graphql-client.js +129 -0
  129. package/plugins/specweave-github/lib/github-graphql-client.ts +181 -0
  130. package/plugins/specweave-github/lib/github-issue-body-generator.js +30 -0
  131. package/plugins/specweave-github/lib/github-issue-body-generator.ts +76 -0
  132. package/plugins/specweave-github/lib/github-issue-body-parser.js +55 -0
  133. package/plugins/specweave-github/lib/github-issue-body-parser.ts +92 -0
  134. package/plugins/specweave-github/lib/github-pull-sync.js +185 -0
  135. package/plugins/specweave-github/lib/github-pull-sync.ts +343 -0
  136. package/plugins/specweave-github/lib/github-push-sync.js +119 -0
  137. package/plugins/specweave-github/lib/github-push-sync.ts +174 -0
  138. package/plugins/specweave-github/lib/github-rate-limiter.js +96 -0
  139. package/plugins/specweave-github/lib/github-rate-limiter.ts +143 -0
  140. package/plugins/specweave-github/lib/github-spec-frontmatter-updater.js +117 -0
  141. package/plugins/specweave-github/lib/github-spec-frontmatter-updater.ts +180 -0
  142. package/plugins/specweave-github/lib/github-sync-orchestrator.js +84 -0
  143. package/plugins/specweave-github/lib/github-sync-orchestrator.ts +156 -0
  144. package/plugins/specweave-github/lib/github-us-auto-closer.js +134 -0
  145. package/plugins/specweave-github/lib/github-us-auto-closer.ts +226 -0
  146. package/plugins/specweave-github/lib/index.js +1 -7
  147. package/plugins/specweave-github/lib/index.ts +1 -4
  148. package/plugins/specweave-github/skills/github-sync/SKILL.md +76 -4
  149. package/plugins/specweave-testing/commands/e2e-setup.md +18 -0
  150. package/plugins/specweave-testing/commands/ui-automate.md +2 -0
  151. package/plugins/specweave-testing/commands/ui-inspect.md +8 -0
  152. package/plugins/specweave-testing/lib/playwright-ci-defaults.d.ts +6 -0
  153. package/plugins/specweave-testing/lib/playwright-ci-defaults.js +14 -0
  154. package/plugins/specweave-testing/lib/playwright-ci-defaults.ts +24 -0
  155. package/plugins/specweave-testing/lib/playwright-cli-detector.js +33 -0
  156. package/plugins/specweave-testing/lib/playwright-cli-detector.ts +48 -0
  157. package/plugins/specweave-testing/lib/playwright-cli-runner.js +58 -0
  158. package/plugins/specweave-testing/lib/playwright-cli-runner.ts +80 -0
  159. package/plugins/specweave-testing/lib/playwright-routing.js +16 -0
  160. package/plugins/specweave-testing/lib/playwright-routing.ts +38 -0
  161. package/plugins/specweave-testing/skills/e2e-testing/SKILL.md +38 -0
  162. package/src/templates/CLAUDE.md.template +7 -0
  163. package/src/templates/config.json.template +9 -1
  164. package/dist/plugins/specweave-github/lib/subtask-sync.d.ts +0 -51
  165. package/dist/plugins/specweave-github/lib/subtask-sync.d.ts.map +0 -1
  166. package/dist/plugins/specweave-github/lib/subtask-sync.js +0 -147
  167. package/dist/plugins/specweave-github/lib/subtask-sync.js.map +0 -1
  168. package/dist/plugins/specweave-github/lib/task-parser.d.ts +0 -37
  169. package/dist/plugins/specweave-github/lib/task-parser.d.ts.map +0 -1
  170. package/dist/plugins/specweave-github/lib/task-parser.js +0 -211
  171. package/dist/plugins/specweave-github/lib/task-parser.js.map +0 -1
  172. package/dist/plugins/specweave-github/lib/task-sync.d.ts +0 -56
  173. package/dist/plugins/specweave-github/lib/task-sync.d.ts.map +0 -1
  174. package/dist/plugins/specweave-github/lib/task-sync.js +0 -375
  175. package/dist/plugins/specweave-github/lib/task-sync.js.map +0 -1
  176. package/plugins/specweave/hooks/validate-completion-conditions.sh +0 -474
  177. package/plugins/specweave-github/lib/subtask-sync.d.ts +0 -51
  178. package/plugins/specweave-github/lib/subtask-sync.d.ts.map +0 -1
  179. package/plugins/specweave-github/lib/subtask-sync.js +0 -154
  180. package/plugins/specweave-github/lib/subtask-sync.js.map +0 -1
  181. package/plugins/specweave-github/lib/subtask-sync.ts +0 -225
  182. package/plugins/specweave-github/lib/task-parser.d.js +0 -0
  183. package/plugins/specweave-github/lib/task-parser.d.ts +0 -37
  184. package/plugins/specweave-github/lib/task-parser.d.ts.map +0 -1
  185. package/plugins/specweave-github/lib/task-parser.js +0 -195
  186. package/plugins/specweave-github/lib/task-parser.js.map +0 -1
  187. package/plugins/specweave-github/lib/task-parser.ts +0 -246
  188. package/plugins/specweave-github/lib/task-sync.d.js +0 -0
  189. package/plugins/specweave-github/lib/task-sync.d.ts +0 -51
  190. package/plugins/specweave-github/lib/task-sync.d.ts.map +0 -1
  191. package/plugins/specweave-github/lib/task-sync.js +0 -415
  192. package/plugins/specweave-github/lib/task-sync.js.map +0 -1
  193. package/plugins/specweave-github/lib/task-sync.ts +0 -451
  194. package/plugins/specweave-github/skills/github-issue-tracker/SKILL.md +0 -496
  195. /package/plugins/specweave/hooks/{stop-auto.sh → _archive/stop-auto-v4-legacy.sh} +0 -0
  196. /package/plugins/{specweave-github/lib/subtask-sync.d.js → specweave-testing/lib/playwright-ci-defaults.d.js} +0 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * GitHub Rate Limiter
3
+ *
4
+ * Shared token-bucket rate limiter for multi-repo GitHub sync.
5
+ * Queries `gh api rate_limit`, tracks cumulative usage, and gates
6
+ * sync operations when approaching API limits.
7
+ *
8
+ * @module github-rate-limiter
9
+ */
10
+ import { execFileNoThrow } from '../../../src/utils/execFileNoThrow.js';
11
+ /** Calls per user story: search + create/update + labels */
12
+ const CALLS_PER_USER_STORY = 3;
13
+ /** Overhead per spec: milestone check, project check */
14
+ const CALLS_PER_SPEC_OVERHEAD = 2;
15
+ export class GitHubRateLimiter {
16
+ constructor(token) {
17
+ this.totalUsed = 0;
18
+ this.knownLimit = 0;
19
+ this.token = token;
20
+ }
21
+ /**
22
+ * Query current GitHub API rate limit via `gh api rate_limit`.
23
+ */
24
+ async checkRateLimit() {
25
+ const env = this.getEnv();
26
+ const result = await execFileNoThrow('gh', ['api', 'rate_limit'], { env });
27
+ if (!result.success) {
28
+ throw new Error(`gh CLI failed: ${result.stderr || result.error?.message || 'unknown error'}`);
29
+ }
30
+ let parsed;
31
+ try {
32
+ parsed = JSON.parse(result.stdout);
33
+ }
34
+ catch {
35
+ throw new Error(`Failed to parse rate limit response: ${result.stdout.slice(0, 100)}`);
36
+ }
37
+ const core = parsed?.resources?.core;
38
+ if (!core || core.remaining === undefined || core.limit === undefined || core.reset === undefined) {
39
+ throw new Error('Rate limit response missing expected fields (resources.core)');
40
+ }
41
+ this.knownLimit = core.limit;
42
+ const percentUsed = core.limit > 0
43
+ ? ((core.limit - core.remaining) / core.limit) * 100
44
+ : 0;
45
+ return {
46
+ remaining: core.remaining,
47
+ limit: core.limit,
48
+ resetAt: new Date(core.reset * 1000),
49
+ percentUsed,
50
+ };
51
+ }
52
+ /**
53
+ * Estimate how many API calls a sync operation will require.
54
+ */
55
+ estimateApiCalls(specCount, userStoryCount) {
56
+ if (specCount === 0 && userStoryCount === 0) {
57
+ return 0;
58
+ }
59
+ return (specCount * CALLS_PER_SPEC_OVERHEAD) + (userStoryCount * CALLS_PER_USER_STORY);
60
+ }
61
+ /**
62
+ * Check whether a sync operation can proceed given the current rate limit.
63
+ */
64
+ async canProceed(estimatedCalls) {
65
+ const status = await this.checkRateLimit();
66
+ if (estimatedCalls > status.remaining) {
67
+ const waitMs = Math.max(0, status.resetAt.getTime() - Date.now());
68
+ return {
69
+ allowed: false,
70
+ waitMs,
71
+ reason: `Rate limit: need ${estimatedCalls} calls but only ${status.remaining}/${status.limit} remaining. Resets in ${Math.ceil(waitMs / 1000)}s`,
72
+ };
73
+ }
74
+ if (status.percentUsed > 90) {
75
+ const waitMs = Math.max(0, status.resetAt.getTime() - Date.now());
76
+ return {
77
+ allowed: false,
78
+ waitMs,
79
+ reason: `Rate limit at ${status.percentUsed.toFixed(0)}% — too high to proceed safely`,
80
+ };
81
+ }
82
+ return { allowed: true };
83
+ }
84
+ /**
85
+ * Record API calls made during a sync operation.
86
+ */
87
+ recordUsage(calls) {
88
+ if (calls < 0) {
89
+ throw new Error('Cannot record negative usage');
90
+ }
91
+ this.totalUsed += calls;
92
+ }
93
+ /**
94
+ * Get the percentage of the known limit used by this limiter instance.
95
+ */
96
+ getUsagePercent() {
97
+ if (this.knownLimit === 0)
98
+ return 0;
99
+ const pct = (this.totalUsed / this.knownLimit) * 100;
100
+ return Math.min(pct, 100);
101
+ }
102
+ getEnv() {
103
+ if (this.token) {
104
+ return { ...process.env, GH_TOKEN: this.token };
105
+ }
106
+ return process.env;
107
+ }
108
+ }
109
+ //# sourceMappingURL=github-rate-limiter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-rate-limiter.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-rate-limiter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * GitHub Spec Frontmatter Updater
3
+ *
4
+ * Updates spec.md YAML frontmatter after push sync to record
5
+ * GitHub issue links for each user story.
6
+ *
7
+ * @module github-spec-frontmatter-updater
8
+ */
9
+ import type { PushSyncResult } from './github-push-sync.js';
10
+ import type { GitHubSyncMetadata } from '../../../src/core/types/sync-profile.js';
11
+ /**
12
+ * Update spec.md frontmatter with GitHub sync results.
13
+ *
14
+ * Reads the spec file, parses YAML frontmatter, merges sync results
15
+ * into the externalLinks.github section, and writes back.
16
+ */
17
+ export declare function updateSpecFrontmatter(specPath: string, syncResult: PushSyncResult, options?: {
18
+ projectV2Id?: string;
19
+ projectV2Number?: number;
20
+ }): Promise<GitHubSyncMetadata>;
21
+ //# sourceMappingURL=github-spec-frontmatter-updater.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-spec-frontmatter-updater.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-spec-frontmatter-updater.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,yCAAyC,CAAC;AAEvG;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,cAAc,EAC1B,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,OAAO,CAAC,kBAAkB,CAAC,CA4E7B"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * GitHub Spec Frontmatter Updater
3
+ *
4
+ * Updates spec.md YAML frontmatter after push sync to record
5
+ * GitHub issue links for each user story.
6
+ *
7
+ * @module github-spec-frontmatter-updater
8
+ */
9
+ import { readFile, writeFile } from 'fs/promises';
10
+ /**
11
+ * Update spec.md frontmatter with GitHub sync results.
12
+ *
13
+ * Reads the spec file, parses YAML frontmatter, merges sync results
14
+ * into the externalLinks.github section, and writes back.
15
+ */
16
+ export async function updateSpecFrontmatter(specPath, syncResult, options) {
17
+ const content = await readFile(specPath, 'utf-8');
18
+ // Parse frontmatter
19
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
20
+ let frontmatter = {};
21
+ let body = content;
22
+ if (fmMatch) {
23
+ frontmatter = parseYamlSimple(fmMatch[1]);
24
+ body = content.slice(fmMatch[0].length);
25
+ }
26
+ // Get existing externalLinks
27
+ const externalLinks = (frontmatter.externalLinks ?? {});
28
+ const existingGithub = (externalLinks.github ?? {});
29
+ const existingUserStories = (existingGithub.userStories ?? {});
30
+ // Build updated user stories map (preserve existing)
31
+ const userStories = { ...existingUserStories };
32
+ const now = new Date().toISOString();
33
+ // Merge created issues
34
+ for (const item of syncResult.created) {
35
+ userStories[item.userStoryId] = {
36
+ issueNumber: item.issueNumber,
37
+ issueUrl: item.issueUrl,
38
+ issueNodeId: item.issueNodeId,
39
+ syncedAt: now,
40
+ };
41
+ }
42
+ // Merge updated issues (preserve existing nodeId)
43
+ for (const item of syncResult.updated) {
44
+ const existing = userStories[item.userStoryId];
45
+ userStories[item.userStoryId] = {
46
+ issueNumber: item.issueNumber,
47
+ issueUrl: item.issueUrl,
48
+ issueNodeId: existing?.issueNodeId,
49
+ syncedAt: now,
50
+ };
51
+ }
52
+ // Determine sync status
53
+ const syncStatus = syncResult.errors.length > 0 ? 'dirty' : 'synced';
54
+ // Build metadata result
55
+ const metadata = {
56
+ syncStatus,
57
+ userStories,
58
+ };
59
+ // ProjectV2 info: prefer options, fall back to existing
60
+ if (options?.projectV2Id) {
61
+ metadata.projectV2Id = options.projectV2Id;
62
+ }
63
+ else if (existingGithub.projectV2Id) {
64
+ metadata.projectV2Id = existingGithub.projectV2Id;
65
+ }
66
+ if (options?.projectV2Number) {
67
+ metadata.projectV2Number = options.projectV2Number;
68
+ }
69
+ else if (existingGithub.projectV2Number) {
70
+ metadata.projectV2Number = existingGithub.projectV2Number;
71
+ }
72
+ // Update frontmatter
73
+ externalLinks.github = metadata;
74
+ frontmatter.externalLinks = externalLinks;
75
+ // Write back
76
+ const newFrontmatter = stringifyYaml(frontmatter);
77
+ const newContent = `---\n${newFrontmatter}\n---${body}`;
78
+ await writeFile(specPath, newContent, 'utf-8');
79
+ return metadata;
80
+ }
81
+ /**
82
+ * Simple YAML parser for spec frontmatter.
83
+ * Handles nested objects, strings, numbers, booleans, null.
84
+ */
85
+ function parseYamlSimple(yaml) {
86
+ const result = {};
87
+ const lines = yaml.split('\n');
88
+ const stack = [
89
+ { obj: result, indent: -1 },
90
+ ];
91
+ for (const line of lines) {
92
+ if (!line.trim() || line.trim().startsWith('#'))
93
+ continue;
94
+ const indent = line.search(/\S/);
95
+ const trimmed = line.trim();
96
+ const colonIdx = trimmed.indexOf(':');
97
+ if (colonIdx === -1)
98
+ continue;
99
+ const key = trimmed.slice(0, colonIdx).trim();
100
+ const rawValue = trimmed.slice(colonIdx + 1).trim();
101
+ // Pop stack to correct indent level
102
+ while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
103
+ stack.pop();
104
+ }
105
+ const parent = stack[stack.length - 1].obj;
106
+ if (rawValue === '' || rawValue === undefined) {
107
+ // Nested object
108
+ const child = {};
109
+ parent[key] = child;
110
+ stack.push({ obj: child, indent });
111
+ }
112
+ else {
113
+ parent[key] = parseYamlValue(rawValue);
114
+ }
115
+ }
116
+ return result;
117
+ }
118
+ function parseYamlValue(raw) {
119
+ if (raw === 'null')
120
+ return null;
121
+ if (raw === 'true')
122
+ return true;
123
+ if (raw === 'false')
124
+ return false;
125
+ if (/^-?\d+$/.test(raw))
126
+ return parseInt(raw, 10);
127
+ if (/^-?\d+\.\d+$/.test(raw))
128
+ return parseFloat(raw);
129
+ if ((raw.startsWith('"') && raw.endsWith('"')) ||
130
+ (raw.startsWith("'") && raw.endsWith("'"))) {
131
+ return raw.slice(1, -1);
132
+ }
133
+ return raw;
134
+ }
135
+ /**
136
+ * Simple YAML stringifier.
137
+ */
138
+ function stringifyYaml(obj, indent = 0) {
139
+ const prefix = ' '.repeat(indent);
140
+ const parts = [];
141
+ for (const [key, value] of Object.entries(obj)) {
142
+ if (value === null || value === undefined) {
143
+ parts.push(`${prefix}${key}: null`);
144
+ }
145
+ else if (typeof value === 'object' && !Array.isArray(value)) {
146
+ parts.push(`${prefix}${key}:`);
147
+ parts.push(stringifyYaml(value, indent + 1));
148
+ }
149
+ else if (typeof value === 'string') {
150
+ parts.push(`${prefix}${key}: "${value}"`);
151
+ }
152
+ else if (typeof value === 'boolean' || typeof value === 'number') {
153
+ parts.push(`${prefix}${key}: ${value}`);
154
+ }
155
+ else {
156
+ parts.push(`${prefix}${key}: ${JSON.stringify(value)}`);
157
+ }
158
+ }
159
+ return parts.join('\n');
160
+ }
161
+ //# sourceMappingURL=github-spec-frontmatter-updater.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-spec-frontmatter-updater.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-spec-frontmatter-updater.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * GitHub Sync Orchestrator — Wires push sync, Projects V2, and frontmatter updates
3
+ *
4
+ * Composes all sync sub-components into a single flow:
5
+ * 1. Push user stories → GitHub issues
6
+ * 2. (Optional) Add issues to Projects V2 board
7
+ * 3. (Optional) Set Status/Priority fields on V2 items
8
+ * 4. Update spec frontmatter with sync results
9
+ *
10
+ * @module github-sync-orchestrator
11
+ */
12
+ import type { UserStoryForSync, PushSyncResult } from './github-push-sync.js';
13
+ import type { FieldSyncResult } from './github-field-sync.js';
14
+ import type { GitHubSyncMetadata } from '../../../src/core/types/sync-profile.js';
15
+ export interface SyncOrchestratorConfig {
16
+ owner: string;
17
+ repo: string;
18
+ token?: string;
19
+ dryRun?: boolean;
20
+ projectV2Enabled?: boolean;
21
+ projectV2Number?: number;
22
+ projectV2Id?: string;
23
+ statusFieldMapping?: Record<string, string>;
24
+ priorityFieldMapping?: Record<string, string>;
25
+ }
26
+ export interface ProjectV2Result {
27
+ projectId: string;
28
+ projectNumber: number;
29
+ itemIds: string[];
30
+ fieldSyncResult: FieldSyncResult;
31
+ }
32
+ export interface SyncOrchestratorResult {
33
+ pushResult: PushSyncResult;
34
+ projectV2Result?: ProjectV2Result;
35
+ frontmatterResult: GitHubSyncMetadata;
36
+ }
37
+ export declare class GitHubSyncOrchestrator {
38
+ private config;
39
+ constructor(config: SyncOrchestratorConfig);
40
+ /**
41
+ * Run the full sync flow for a spec.
42
+ */
43
+ syncSpec(specPath: string, userStories: UserStoryForSync[]): Promise<SyncOrchestratorResult>;
44
+ private syncProjectV2;
45
+ }
46
+ //# sourceMappingURL=github-sync-orchestrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-sync-orchestrator.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-sync-orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAElF,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,oBAAoB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,eAAe,EAAE,eAAe,CAAC;CAClC;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,EAAE,cAAc,CAAC;IAC3B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,iBAAiB,EAAE,kBAAkB,CAAC;CACvC;AAED,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAyB;gBAE3B,MAAM,EAAE,sBAAsB;IAI1C;;OAEG;IACG,QAAQ,CACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,gBAAgB,EAAE,GAC9B,OAAO,CAAC,sBAAsB,CAAC;YAoCpB,aAAa;CA4D5B"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * GitHub Sync Orchestrator — Wires push sync, Projects V2, and frontmatter updates
3
+ *
4
+ * Composes all sync sub-components into a single flow:
5
+ * 1. Push user stories → GitHub issues
6
+ * 2. (Optional) Add issues to Projects V2 board
7
+ * 3. (Optional) Set Status/Priority fields on V2 items
8
+ * 4. Update spec frontmatter with sync results
9
+ *
10
+ * @module github-sync-orchestrator
11
+ */
12
+ import { pushSyncUserStories } from './github-push-sync.js';
13
+ import { GitHubBoardResolverV2 } from './github-board-resolver-v2.js';
14
+ import { GitHubFieldSync } from './github-field-sync.js';
15
+ import { updateSpecFrontmatter } from './github-spec-frontmatter-updater.js';
16
+ import { GitHubGraphQLClient } from './github-graphql-client.js';
17
+ export class GitHubSyncOrchestrator {
18
+ constructor(config) {
19
+ this.config = config;
20
+ }
21
+ /**
22
+ * Run the full sync flow for a spec.
23
+ */
24
+ async syncSpec(specPath, userStories) {
25
+ // Step 1: Push sync — create/update GitHub issues
26
+ const pushResult = await pushSyncUserStories(userStories, {
27
+ owner: this.config.owner,
28
+ repo: this.config.repo,
29
+ token: this.config.token,
30
+ dryRun: this.config.dryRun,
31
+ });
32
+ // Step 2: Projects V2 (optional, skip in dry run)
33
+ let projectV2Result;
34
+ if (this.config.projectV2Enabled && !this.config.dryRun) {
35
+ projectV2Result = await this.syncProjectV2(pushResult, userStories);
36
+ }
37
+ // Step 3: Update spec frontmatter
38
+ const frontmatterOptions = {};
39
+ if (projectV2Result) {
40
+ frontmatterOptions.projectV2Id = projectV2Result.projectId;
41
+ frontmatterOptions.projectV2Number = projectV2Result.projectNumber;
42
+ }
43
+ const frontmatterResult = await updateSpecFrontmatter(specPath, pushResult, frontmatterOptions);
44
+ return {
45
+ pushResult,
46
+ projectV2Result,
47
+ frontmatterResult,
48
+ };
49
+ }
50
+ async syncProjectV2(pushResult, userStories) {
51
+ const graphqlClient = new GitHubGraphQLClient(this.config.token);
52
+ // Find or create the Projects V2 board
53
+ const boardResolver = new GitHubBoardResolverV2(graphqlClient, {
54
+ owner: this.config.owner,
55
+ projectV2Number: this.config.projectV2Number,
56
+ projectV2Id: this.config.projectV2Id,
57
+ });
58
+ const project = await boardResolver.findOrCreateProject('SpecWeave Sync Board');
59
+ // Collect issue node IDs from created issues
60
+ const nodeIds = pushResult.created
61
+ .filter(item => item.issueNodeId)
62
+ .map(item => item.issueNodeId);
63
+ // Add issues to project
64
+ const itemIds = await boardResolver.addIssuesToProject(project.id, nodeIds);
65
+ // Build a map from nodeId → user story for field sync
66
+ const nodeIdToStory = new Map();
67
+ for (const created of pushResult.created) {
68
+ if (created.issueNodeId) {
69
+ const story = userStories.find(s => s.id === created.userStoryId);
70
+ if (story) {
71
+ nodeIdToStory.set(created.issueNodeId, story);
72
+ }
73
+ }
74
+ }
75
+ // Sync Status and Priority fields
76
+ const fieldSync = new GitHubFieldSync(graphqlClient, {
77
+ projectId: project.id,
78
+ statusFieldMapping: this.config.statusFieldMapping,
79
+ priorityFieldMapping: this.config.priorityFieldMapping,
80
+ });
81
+ const fieldSyncItems = itemIds.map((itemId, idx) => {
82
+ const nodeId = nodeIds[idx];
83
+ const story = nodeId ? nodeIdToStory.get(nodeId) : undefined;
84
+ return {
85
+ itemId,
86
+ status: story?.status,
87
+ priority: story?.priority,
88
+ };
89
+ });
90
+ const fieldSyncResult = await fieldSync.syncItemFields(fieldSyncItems);
91
+ return {
92
+ projectId: project.id,
93
+ projectNumber: project.number,
94
+ itemIds,
95
+ fieldSyncResult,
96
+ };
97
+ }
98
+ }
99
+ //# sourceMappingURL=github-sync-orchestrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-sync-orchestrator.js","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-sync-orchestrator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * GitHub US Auto-Closer — Closes GitHub issues when all ACs are complete
3
+ *
4
+ * For each affected user story, checks if ALL acceptance criteria are
5
+ * marked complete in spec.md. If so, posts a completion comment and
6
+ * closes the associated GitHub issue.
7
+ *
8
+ * @module github-us-auto-closer
9
+ */
10
+ export interface AutoCloseOptions {
11
+ owner: string;
12
+ repo: string;
13
+ token?: string;
14
+ }
15
+ export interface AutoCloseResult {
16
+ closed: Array<{
17
+ usId: string;
18
+ issueNumber: number;
19
+ }>;
20
+ skipped: Array<{
21
+ usId: string;
22
+ reason: string;
23
+ }>;
24
+ errors: Array<{
25
+ usId: string;
26
+ error: string;
27
+ }>;
28
+ }
29
+ /**
30
+ * Auto-close GitHub issues for user stories with all ACs complete.
31
+ *
32
+ * For each affected US:
33
+ * 1. Parse AC states from spec.md
34
+ * 2. Skip if not all ACs complete
35
+ * 3. Look up GitHub issue link from frontmatter
36
+ * 4. Check if issue already closed (idempotent)
37
+ * 5. Post completion comment
38
+ * 6. Close issue via `gh issue close`
39
+ *
40
+ * Never throws — all errors captured in result.errors.
41
+ */
42
+ export declare function autoCloseCompletedUserStories(incrementId: string, affectedUSIds: string[], specPath: string, options: AutoCloseOptions): Promise<AutoCloseResult>;
43
+ //# sourceMappingURL=github-us-auto-closer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-us-auto-closer.d.ts","sourceRoot":"","sources":["../../../../plugins/specweave-github/lib/github-us-auto-closer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAaD;;;;;;;;;;;;GAYG;AACH,wBAAsB,6BAA6B,CACjD,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EAAE,EACvB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CAsF1B"}