specweave 0.17.16 → 0.17.19

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 (232) hide show
  1. package/CLAUDE.md +405 -2495
  2. package/README.md +92 -2
  3. package/dist/locales/de/.gitkeep +0 -0
  4. package/dist/locales/de/cli.json +108 -0
  5. package/dist/locales/en/cli.json +287 -0
  6. package/dist/locales/en/errors.json +7 -0
  7. package/dist/locales/en/templates.json +6 -0
  8. package/dist/locales/es/.gitkeep +0 -0
  9. package/dist/locales/es/cli.json +41 -0
  10. package/dist/locales/fr/.gitkeep +0 -0
  11. package/dist/locales/fr/cli.json +108 -0
  12. package/dist/locales/ja/.gitkeep +0 -0
  13. package/dist/locales/ja/cli.json +108 -0
  14. package/dist/locales/ko/.gitkeep +0 -0
  15. package/dist/locales/ko/cli.json +108 -0
  16. package/dist/locales/pt/.gitkeep +0 -0
  17. package/dist/locales/pt/cli.json +108 -0
  18. package/dist/locales/ru/.gitkeep +0 -0
  19. package/dist/locales/ru/cli.json +269 -0
  20. package/dist/locales/zh/.gitkeep +0 -0
  21. package/dist/locales/zh/cli.json +108 -0
  22. package/dist/plugins/specweave/lib/hooks/sync-living-docs.d.ts.map +1 -1
  23. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js +188 -36
  24. package/dist/plugins/specweave/lib/hooks/sync-living-docs.js.map +1 -1
  25. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.d.ts.map +1 -1
  26. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js +65 -6
  27. package/dist/plugins/specweave-ado/lib/ado-spec-content-sync.js.map +1 -1
  28. package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts +54 -0
  29. package/dist/plugins/specweave-ado/lib/ado-status-sync.d.ts.map +1 -0
  30. package/dist/plugins/specweave-ado/lib/ado-status-sync.js +86 -0
  31. package/dist/plugins/specweave-ado/lib/ado-status-sync.js.map +1 -0
  32. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts +25 -0
  33. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.d.ts.map +1 -0
  34. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js +191 -0
  35. package/dist/plugins/specweave-ado/lib/enhanced-ado-sync.js.map +1 -0
  36. package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts +139 -0
  37. package/dist/plugins/specweave-github/lib/duplicate-detector.d.ts.map +1 -0
  38. package/dist/plugins/specweave-github/lib/duplicate-detector.js +389 -0
  39. package/dist/plugins/specweave-github/lib/duplicate-detector.js.map +1 -0
  40. package/dist/plugins/specweave-github/lib/enhanced-github-sync.d.ts +26 -0
  41. package/dist/plugins/specweave-github/lib/enhanced-github-sync.d.ts.map +1 -0
  42. package/dist/plugins/specweave-github/lib/enhanced-github-sync.js +249 -0
  43. package/dist/plugins/specweave-github/lib/enhanced-github-sync.js.map +1 -0
  44. package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts +63 -0
  45. package/dist/plugins/specweave-github/lib/epic-content-builder.d.ts.map +1 -0
  46. package/dist/plugins/specweave-github/lib/epic-content-builder.js +216 -0
  47. package/dist/plugins/specweave-github/lib/epic-content-builder.js.map +1 -0
  48. package/dist/plugins/specweave-github/lib/github-client.d.ts +1 -1
  49. package/dist/plugins/specweave-github/lib/github-client.d.ts.map +1 -1
  50. package/dist/plugins/specweave-github/lib/github-client.js +25 -13
  51. package/dist/plugins/specweave-github/lib/github-client.js.map +1 -1
  52. package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts +83 -0
  53. package/dist/plugins/specweave-github/lib/github-epic-sync.d.ts.map +1 -0
  54. package/dist/plugins/specweave-github/lib/github-epic-sync.js +466 -0
  55. package/dist/plugins/specweave-github/lib/github-epic-sync.js.map +1 -0
  56. package/dist/plugins/specweave-github/lib/github-status-sync.d.ts +43 -0
  57. package/dist/plugins/specweave-github/lib/github-status-sync.d.ts.map +1 -0
  58. package/dist/plugins/specweave-github/lib/github-status-sync.js +82 -0
  59. package/dist/plugins/specweave-github/lib/github-status-sync.js.map +1 -0
  60. package/dist/plugins/specweave-github/lib/task-sync.d.ts +5 -0
  61. package/dist/plugins/specweave-github/lib/task-sync.d.ts.map +1 -1
  62. package/dist/plugins/specweave-github/lib/task-sync.js +38 -2
  63. package/dist/plugins/specweave-github/lib/task-sync.js.map +1 -1
  64. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts +28 -0
  65. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.d.ts.map +1 -0
  66. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js +156 -0
  67. package/dist/plugins/specweave-jira/lib/enhanced-jira-sync.js.map +1 -0
  68. package/dist/plugins/specweave-jira/lib/jira-epic-sync.d.ts +66 -0
  69. package/dist/plugins/specweave-jira/lib/jira-epic-sync.d.ts.map +1 -0
  70. package/dist/plugins/specweave-jira/lib/jira-epic-sync.js +274 -0
  71. package/dist/plugins/specweave-jira/lib/jira-epic-sync.js.map +1 -0
  72. package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts +56 -0
  73. package/dist/plugins/specweave-jira/lib/jira-status-sync.d.ts.map +1 -0
  74. package/dist/plugins/specweave-jira/lib/jira-status-sync.js +93 -0
  75. package/dist/plugins/specweave-jira/lib/jira-status-sync.js.map +1 -0
  76. package/dist/spec-parser.js +629 -0
  77. package/dist/src/cli/commands/init.d.ts.map +1 -1
  78. package/dist/src/cli/commands/init.js +107 -3
  79. package/dist/src/cli/commands/init.js.map +1 -1
  80. package/dist/src/cli/helpers/issue-tracker/index.d.ts.map +1 -1
  81. package/dist/src/cli/helpers/issue-tracker/index.js +48 -3
  82. package/dist/src/cli/helpers/issue-tracker/index.js.map +1 -1
  83. package/dist/src/core/deduplication/command-deduplicator.d.ts +166 -0
  84. package/dist/src/core/deduplication/command-deduplicator.d.ts.map +1 -0
  85. package/dist/src/core/deduplication/command-deduplicator.js +254 -0
  86. package/dist/src/core/deduplication/command-deduplicator.js.map +1 -0
  87. package/dist/src/core/living-docs/hierarchy-mapper.d.ts +142 -0
  88. package/dist/src/core/living-docs/hierarchy-mapper.d.ts.map +1 -0
  89. package/dist/src/core/living-docs/hierarchy-mapper.js +453 -0
  90. package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -0
  91. package/dist/src/core/living-docs/index.d.ts +10 -84
  92. package/dist/src/core/living-docs/index.d.ts.map +1 -1
  93. package/dist/src/core/living-docs/index.js +10 -164
  94. package/dist/src/core/living-docs/index.js.map +1 -1
  95. package/dist/src/core/living-docs/spec-distributor.d.ts +106 -0
  96. package/dist/src/core/living-docs/spec-distributor.d.ts.map +1 -0
  97. package/dist/src/core/living-docs/spec-distributor.js +823 -0
  98. package/dist/src/core/living-docs/spec-distributor.js.map +1 -0
  99. package/dist/src/core/living-docs/types.d.ts +201 -0
  100. package/dist/src/core/living-docs/types.d.ts.map +1 -0
  101. package/dist/src/core/living-docs/types.js +15 -0
  102. package/dist/src/core/living-docs/types.js.map +1 -0
  103. package/dist/src/core/logging/prompt-logger.d.ts +70 -0
  104. package/dist/src/core/logging/prompt-logger.d.ts.map +1 -0
  105. package/dist/src/core/logging/prompt-logger.js +247 -0
  106. package/dist/src/core/logging/prompt-logger.js.map +1 -0
  107. package/dist/src/core/status-line/status-line-manager.d.ts +15 -24
  108. package/dist/src/core/status-line/status-line-manager.d.ts.map +1 -1
  109. package/dist/src/core/status-line/status-line-manager.js +33 -70
  110. package/dist/src/core/status-line/status-line-manager.js.map +1 -1
  111. package/dist/src/core/status-line/types.d.ts +19 -31
  112. package/dist/src/core/status-line/types.d.ts.map +1 -1
  113. package/dist/src/core/status-line/types.js +5 -9
  114. package/dist/src/core/status-line/types.js.map +1 -1
  115. package/dist/src/core/sync/conflict-resolver.d.ts +66 -0
  116. package/dist/src/core/sync/conflict-resolver.d.ts.map +1 -0
  117. package/dist/src/core/sync/conflict-resolver.js +108 -0
  118. package/dist/src/core/sync/conflict-resolver.js.map +1 -0
  119. package/dist/src/core/sync/enhanced-content-builder.d.ts +55 -0
  120. package/dist/src/core/sync/enhanced-content-builder.d.ts.map +1 -0
  121. package/dist/src/core/sync/enhanced-content-builder.js +202 -0
  122. package/dist/src/core/sync/enhanced-content-builder.js.map +1 -0
  123. package/dist/src/core/sync/label-detector.d.ts +66 -0
  124. package/dist/src/core/sync/label-detector.d.ts.map +1 -0
  125. package/dist/src/core/sync/label-detector.js +211 -0
  126. package/dist/src/core/sync/label-detector.js.map +1 -0
  127. package/dist/src/core/sync/retry-logic.d.ts +64 -0
  128. package/dist/src/core/sync/retry-logic.d.ts.map +1 -0
  129. package/dist/src/core/sync/retry-logic.js +165 -0
  130. package/dist/src/core/sync/retry-logic.js.map +1 -0
  131. package/dist/src/core/sync/spec-content-sync.d.ts +88 -0
  132. package/dist/src/core/sync/spec-content-sync.d.ts.map +1 -0
  133. package/dist/src/core/sync/spec-content-sync.js +5 -0
  134. package/dist/src/core/sync/spec-content-sync.js.map +1 -0
  135. package/dist/src/core/sync/spec-increment-mapper.d.ts +100 -0
  136. package/dist/src/core/sync/spec-increment-mapper.d.ts.map +1 -0
  137. package/dist/src/core/sync/spec-increment-mapper.js +424 -0
  138. package/dist/src/core/sync/spec-increment-mapper.js.map +1 -0
  139. package/dist/src/core/sync/status-cache.d.ts +91 -0
  140. package/dist/src/core/sync/status-cache.d.ts.map +1 -0
  141. package/dist/src/core/sync/status-cache.js +140 -0
  142. package/dist/src/core/sync/status-cache.js.map +1 -0
  143. package/dist/src/core/sync/status-mapper.d.ts +69 -0
  144. package/dist/src/core/sync/status-mapper.d.ts.map +1 -0
  145. package/dist/src/core/sync/status-mapper.js +90 -0
  146. package/dist/src/core/sync/status-mapper.js.map +1 -0
  147. package/dist/src/core/sync/status-sync-engine.d.ts +162 -0
  148. package/dist/src/core/sync/status-sync-engine.d.ts.map +1 -0
  149. package/dist/src/core/sync/status-sync-engine.js +347 -0
  150. package/dist/src/core/sync/status-sync-engine.js.map +1 -0
  151. package/dist/src/core/sync/sync-event-logger.d.ts +99 -0
  152. package/dist/src/core/sync/sync-event-logger.d.ts.map +1 -0
  153. package/dist/src/core/sync/sync-event-logger.js +103 -0
  154. package/dist/src/core/sync/sync-event-logger.js.map +1 -0
  155. package/dist/src/core/sync/types.d.ts +52 -0
  156. package/dist/src/core/sync/types.d.ts.map +1 -0
  157. package/dist/src/core/sync/types.js +5 -0
  158. package/dist/src/core/sync/types.js.map +1 -0
  159. package/dist/src/core/sync/workflow-detector.d.ts +95 -0
  160. package/dist/src/core/sync/workflow-detector.d.ts.map +1 -0
  161. package/dist/src/core/sync/workflow-detector.js +175 -0
  162. package/dist/src/core/sync/workflow-detector.js.map +1 -0
  163. package/dist/src/core/types/config.d.ts +51 -0
  164. package/dist/src/core/types/config.d.ts.map +1 -1
  165. package/dist/src/core/types/config.js +47 -0
  166. package/dist/src/core/types/config.js.map +1 -1
  167. package/dist/src/core/types/increment-metadata.d.ts +4 -0
  168. package/dist/src/core/types/increment-metadata.d.ts.map +1 -1
  169. package/dist/src/core/types/increment-metadata.js.map +1 -1
  170. package/dist/src/utils/github-url.d.ts +53 -0
  171. package/dist/src/utils/github-url.d.ts.map +1 -0
  172. package/dist/src/utils/github-url.js +90 -0
  173. package/dist/src/utils/github-url.js.map +1 -0
  174. package/dist/src/utils/spec-parser.d.ts +145 -0
  175. package/dist/src/utils/spec-parser.d.ts.map +1 -0
  176. package/dist/src/utils/spec-parser.js +640 -0
  177. package/dist/src/utils/spec-parser.js.map +1 -0
  178. package/dist/tsconfig.tsbuildinfo +1 -0
  179. package/package.json +1 -1
  180. package/plugins/specweave/agents/pm/AGENT.md +160 -13
  181. package/plugins/specweave/agents/pm/templates/increment-spec.md +158 -0
  182. package/plugins/specweave/agents/pm/templates/living-docs-spec.md +113 -0
  183. package/plugins/specweave/commands/specweave-done.md +163 -0
  184. package/plugins/specweave/commands/specweave.md +70 -405
  185. package/plugins/specweave/hooks/hooks.json +4 -0
  186. package/plugins/specweave/hooks/lib/sync-spec-content.sh +2 -2
  187. package/plugins/specweave/hooks/lib/update-status-line.sh +79 -111
  188. package/plugins/specweave/hooks/post-increment-planning.sh +133 -37
  189. package/plugins/specweave/hooks/pre-command-deduplication.sh +86 -0
  190. package/plugins/specweave/lib/hooks/sync-living-docs.js +139 -34
  191. package/plugins/specweave/lib/hooks/sync-living-docs.ts +234 -38
  192. package/plugins/specweave/skills/SKILLS-INDEX.md +4 -24
  193. package/plugins/specweave/skills/increment-planner/SKILL.md +94 -0
  194. package/plugins/specweave/skills/increment-work-router/SKILL.md +466 -0
  195. package/plugins/specweave-ado/commands/specweave-ado-sync-spec.md +1 -1
  196. package/plugins/specweave-ado/lib/ado-spec-content-sync.js +49 -5
  197. package/plugins/specweave-ado/lib/ado-spec-content-sync.ts +72 -6
  198. package/plugins/specweave-ado/lib/ado-status-sync.js +80 -0
  199. package/plugins/specweave-ado/lib/ado-status-sync.ts +121 -0
  200. package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
  201. package/plugins/specweave-github/commands/specweave-github-cleanup-duplicates.md +205 -0
  202. package/plugins/specweave-github/commands/specweave-github-sync-epic.md +248 -0
  203. package/plugins/specweave-github/commands/specweave-github-sync-spec.md +1 -1
  204. package/plugins/specweave-github/hooks/post-task-completion.sh +32 -0
  205. package/plugins/specweave-github/lib/duplicate-detector.js +370 -0
  206. package/plugins/specweave-github/lib/duplicate-detector.ts +525 -0
  207. package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
  208. package/plugins/specweave-github/lib/enhanced-github-sync.ts +322 -0
  209. package/plugins/specweave-github/lib/epic-content-builder.js +227 -0
  210. package/plugins/specweave-github/lib/epic-content-builder.ts +317 -0
  211. package/plugins/specweave-github/lib/github-client.js +21 -10
  212. package/plugins/specweave-github/lib/github-client.ts +27 -16
  213. package/plugins/specweave-github/lib/github-epic-sync.js +488 -0
  214. package/plugins/specweave-github/lib/github-epic-sync.ts +715 -0
  215. package/plugins/specweave-github/lib/github-status-sync.js +71 -0
  216. package/plugins/specweave-github/lib/github-status-sync.ts +107 -0
  217. package/plugins/specweave-github/lib/task-sync.js +33 -2
  218. package/plugins/specweave-github/lib/task-sync.ts +44 -2
  219. package/plugins/specweave-jira/commands/specweave-jira-sync-epic.md +267 -0
  220. package/plugins/specweave-jira/commands/specweave-jira-sync-spec.md +1 -1
  221. package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
  222. package/plugins/specweave-jira/lib/enhanced-jira-sync.ts +196 -0
  223. package/plugins/specweave-jira/lib/jira-epic-sync.js +304 -0
  224. package/plugins/specweave-jira/lib/jira-epic-sync.ts +459 -0
  225. package/plugins/specweave-jira/lib/jira-status-sync.js +79 -0
  226. package/plugins/specweave-jira/lib/jira-status-sync.ts +139 -0
  227. package/plugins/specweave-release/commands/specweave-release-platform.md +1 -1
  228. package/plugins/specweave-release/hooks/post-task-completion.sh +2 -2
  229. package/src/templates/AGENTS.md.template +88 -1
  230. package/src/templates/CLAUDE.md.template +49 -0
  231. package/plugins/specweave/skills/increment-quality-judge/SKILL.md +0 -524
  232. package/plugins/specweave/skills/plugin-installer/SKILL.md +0 -353
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Global Command Deduplication System
3
+ *
4
+ * Prevents ANY command/tool from being invoked twice within a configurable time window.
5
+ * Tracks all SlashCommand, Write, Edit, and other tool invocations.
6
+ *
7
+ * Architecture:
8
+ * - File-based cache: `.specweave/state/command-invocations.json`
9
+ * - Hash-based deduplication: command + args → unique fingerprint
10
+ * - Time-windowed checks: Configurable window (default: 1000ms)
11
+ * - Automatic cleanup: Removes old entries to prevent bloat
12
+ *
13
+ * Usage:
14
+ * ```typescript
15
+ * import { CommandDeduplicator } from './command-deduplicator.js';
16
+ *
17
+ * const dedup = new CommandDeduplicator();
18
+ * const isDuplicate = await dedup.checkDuplicate('/specweave:do', ['0031']);
19
+ *
20
+ * if (isDuplicate) {
21
+ * console.log('⚠️ Duplicate invocation blocked!');
22
+ * return;
23
+ * }
24
+ *
25
+ * await dedup.recordInvocation('/specweave:do', ['0031']);
26
+ * // ... execute command
27
+ * ```
28
+ *
29
+ * @module core/deduplication
30
+ */
31
+ /**
32
+ * Invocation record stored in cache
33
+ */
34
+ export interface InvocationRecord {
35
+ /** Unique fingerprint of command + args */
36
+ fingerprint: string;
37
+ /** Command name (e.g., '/specweave:do') */
38
+ command: string;
39
+ /** Command arguments */
40
+ args: string[];
41
+ /** Timestamp when invoked (ms since epoch) */
42
+ timestamp: number;
43
+ /** Human-readable timestamp */
44
+ date: string;
45
+ }
46
+ /**
47
+ * Cache structure
48
+ */
49
+ export interface InvocationCache {
50
+ /** List of invocation records */
51
+ invocations: InvocationRecord[];
52
+ /** Last cleanup timestamp */
53
+ lastCleanup: number;
54
+ /** Total invocations tracked */
55
+ totalInvocations: number;
56
+ /** Total duplicates blocked */
57
+ totalDuplicatesBlocked: number;
58
+ }
59
+ /**
60
+ * Configuration for deduplication
61
+ */
62
+ export interface DeduplicationConfig {
63
+ /** Time window in milliseconds to check for duplicates (default: 1000ms) */
64
+ windowMs?: number;
65
+ /** Path to cache file (default: .specweave/state/command-invocations.json) */
66
+ cachePath?: string;
67
+ /** Maximum cache entries before cleanup (default: 1000) */
68
+ maxCacheSize?: number;
69
+ /** Enable debug logging (default: false) */
70
+ debug?: boolean;
71
+ /** Cleanup interval in milliseconds (default: 60000ms = 1 minute) */
72
+ cleanupIntervalMs?: number;
73
+ }
74
+ /**
75
+ * Global command deduplication system
76
+ */
77
+ export declare class CommandDeduplicator {
78
+ private projectRoot;
79
+ private config;
80
+ private cache;
81
+ private lastCleanupCheck;
82
+ /**
83
+ * Create new deduplicator instance
84
+ *
85
+ * @param config - Configuration options
86
+ * @param projectRoot - Project root directory (default: process.cwd())
87
+ */
88
+ constructor(config?: DeduplicationConfig, projectRoot?: string);
89
+ /**
90
+ * Check if command invocation is a duplicate
91
+ *
92
+ * @param command - Command name (e.g., '/specweave:do')
93
+ * @param args - Command arguments
94
+ * @returns true if duplicate detected, false otherwise
95
+ */
96
+ checkDuplicate(command: string, args?: string[]): Promise<boolean>;
97
+ /**
98
+ * Record command invocation
99
+ *
100
+ * @param command - Command name
101
+ * @param args - Command arguments
102
+ */
103
+ recordInvocation(command: string, args?: string[]): Promise<void>;
104
+ /**
105
+ * Create unique fingerprint for command + args
106
+ *
107
+ * @param command - Command name
108
+ * @param args - Command arguments
109
+ * @returns SHA256 hash of command + args
110
+ */
111
+ private createFingerprint;
112
+ /**
113
+ * Load cache from disk
114
+ *
115
+ * @returns Invocation cache
116
+ */
117
+ private loadCache;
118
+ /**
119
+ * Save cache to disk
120
+ */
121
+ private saveCache;
122
+ /**
123
+ * Clean up old invocation records
124
+ *
125
+ * Removes records older than 10x the deduplication window to prevent cache bloat.
126
+ */
127
+ private cleanup;
128
+ /**
129
+ * Get statistics about deduplication
130
+ *
131
+ * @returns Statistics object
132
+ */
133
+ getStats(): {
134
+ totalInvocations: number;
135
+ totalDuplicatesBlocked: number;
136
+ currentCacheSize: number;
137
+ lastCleanup: string;
138
+ };
139
+ /**
140
+ * Clear all cached invocations (useful for testing)
141
+ */
142
+ clear(): Promise<void>;
143
+ }
144
+ /**
145
+ * Get global deduplicator instance
146
+ *
147
+ * @param config - Configuration (only used on first call)
148
+ * @returns Global deduplicator instance
149
+ */
150
+ export declare function getGlobalDeduplicator(config?: DeduplicationConfig): CommandDeduplicator;
151
+ /**
152
+ * Convenience function: Check if command is duplicate
153
+ *
154
+ * @param command - Command name
155
+ * @param args - Command arguments
156
+ * @returns true if duplicate, false otherwise
157
+ */
158
+ export declare function isDuplicate(command: string, args?: string[]): Promise<boolean>;
159
+ /**
160
+ * Convenience function: Record command invocation
161
+ *
162
+ * @param command - Command name
163
+ * @param args - Command arguments
164
+ */
165
+ export declare function recordCommand(command: string, args?: string[]): Promise<void>;
166
+ //# sourceMappingURL=command-deduplicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-deduplicator.d.ts","sourceRoot":"","sources":["../../../../src/core/deduplication/command-deduplicator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAMH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IAEpB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAEhB,wBAAwB;IACxB,IAAI,EAAE,MAAM,EAAE,CAAC;IAEf,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAElB,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAEhC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;IAEpB,gCAAgC;IAChC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,+BAA+B;IAC/B,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,qEAAqE;IACrE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAWgB,OAAO,CAAC,WAAW;IAVjE,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,gBAAgB,CAAa;IAErC;;;;;OAKG;gBACS,MAAM,GAAE,mBAAwB,EAAU,WAAW,GAAE,MAAsB;IAYzF;;;;;;OAMG;IACU,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAiCnF;;;;;OAKG;IACU,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BlF;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;;;OAIG;IACH,OAAO,CAAC,SAAS;IA0BjB;;OAEG;YACW,SAAS;IAavB;;;;OAIG;YACW,OAAO;IAsBrB;;;;OAIG;IACI,QAAQ,IAAI;QACjB,gBAAgB,EAAE,MAAM,CAAC;QACzB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB;IASD;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAapC;AAOD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,CAKvF;AAED;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAExF;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAEvF"}
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Global Command Deduplication System
3
+ *
4
+ * Prevents ANY command/tool from being invoked twice within a configurable time window.
5
+ * Tracks all SlashCommand, Write, Edit, and other tool invocations.
6
+ *
7
+ * Architecture:
8
+ * - File-based cache: `.specweave/state/command-invocations.json`
9
+ * - Hash-based deduplication: command + args → unique fingerprint
10
+ * - Time-windowed checks: Configurable window (default: 1000ms)
11
+ * - Automatic cleanup: Removes old entries to prevent bloat
12
+ *
13
+ * Usage:
14
+ * ```typescript
15
+ * import { CommandDeduplicator } from './command-deduplicator.js';
16
+ *
17
+ * const dedup = new CommandDeduplicator();
18
+ * const isDuplicate = await dedup.checkDuplicate('/specweave:do', ['0031']);
19
+ *
20
+ * if (isDuplicate) {
21
+ * console.log('⚠️ Duplicate invocation blocked!');
22
+ * return;
23
+ * }
24
+ *
25
+ * await dedup.recordInvocation('/specweave:do', ['0031']);
26
+ * // ... execute command
27
+ * ```
28
+ *
29
+ * @module core/deduplication
30
+ */
31
+ import * as fs from 'fs-extra';
32
+ import * as path from 'path';
33
+ import * as crypto from 'crypto';
34
+ /**
35
+ * Global command deduplication system
36
+ */
37
+ export class CommandDeduplicator {
38
+ /**
39
+ * Create new deduplicator instance
40
+ *
41
+ * @param config - Configuration options
42
+ * @param projectRoot - Project root directory (default: process.cwd())
43
+ */
44
+ constructor(config = {}, projectRoot = process.cwd()) {
45
+ this.projectRoot = projectRoot;
46
+ this.lastCleanupCheck = 0;
47
+ this.config = {
48
+ windowMs: config.windowMs ?? 1000,
49
+ cachePath: config.cachePath ?? path.join(projectRoot, '.specweave', 'state', 'command-invocations.json'),
50
+ maxCacheSize: config.maxCacheSize ?? 1000,
51
+ debug: config.debug ?? false,
52
+ cleanupIntervalMs: config.cleanupIntervalMs ?? 60000
53
+ };
54
+ this.cache = this.loadCache();
55
+ }
56
+ /**
57
+ * Check if command invocation is a duplicate
58
+ *
59
+ * @param command - Command name (e.g., '/specweave:do')
60
+ * @param args - Command arguments
61
+ * @returns true if duplicate detected, false otherwise
62
+ */
63
+ async checkDuplicate(command, args = []) {
64
+ const fingerprint = this.createFingerprint(command, args);
65
+ const now = Date.now();
66
+ const windowStart = now - this.config.windowMs;
67
+ // Check for recent invocations with same fingerprint
68
+ const recentDuplicates = this.cache.invocations.filter(inv => inv.fingerprint === fingerprint &&
69
+ inv.timestamp >= windowStart);
70
+ if (recentDuplicates.length > 0) {
71
+ const mostRecent = recentDuplicates[recentDuplicates.length - 1];
72
+ const timeSince = now - mostRecent.timestamp;
73
+ if (this.config.debug) {
74
+ console.log(`[CommandDeduplicator] 🚫 DUPLICATE DETECTED!`);
75
+ console.log(` Command: ${command}`);
76
+ console.log(` Args: ${JSON.stringify(args)}`);
77
+ console.log(` Time since last: ${timeSince}ms`);
78
+ console.log(` Window: ${this.config.windowMs}ms`);
79
+ }
80
+ // Increment duplicate counter
81
+ this.cache.totalDuplicatesBlocked++;
82
+ await this.saveCache();
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+ /**
88
+ * Record command invocation
89
+ *
90
+ * @param command - Command name
91
+ * @param args - Command arguments
92
+ */
93
+ async recordInvocation(command, args = []) {
94
+ const fingerprint = this.createFingerprint(command, args);
95
+ const now = Date.now();
96
+ const record = {
97
+ fingerprint,
98
+ command,
99
+ args,
100
+ timestamp: now,
101
+ date: new Date(now).toISOString()
102
+ };
103
+ this.cache.invocations.push(record);
104
+ this.cache.totalInvocations++;
105
+ if (this.config.debug) {
106
+ console.log(`[CommandDeduplicator] ✅ Recorded invocation: ${command} ${args.join(' ')}`);
107
+ }
108
+ // Trigger cleanup if needed
109
+ if (now - this.lastCleanupCheck > this.config.cleanupIntervalMs) {
110
+ await this.cleanup();
111
+ this.lastCleanupCheck = now;
112
+ }
113
+ await this.saveCache();
114
+ }
115
+ /**
116
+ * Create unique fingerprint for command + args
117
+ *
118
+ * @param command - Command name
119
+ * @param args - Command arguments
120
+ * @returns SHA256 hash of command + args
121
+ */
122
+ createFingerprint(command, args) {
123
+ const data = JSON.stringify({ command, args });
124
+ return crypto.createHash('sha256').update(data).digest('hex');
125
+ }
126
+ /**
127
+ * Load cache from disk
128
+ *
129
+ * @returns Invocation cache
130
+ */
131
+ loadCache() {
132
+ try {
133
+ if (fs.existsSync(this.config.cachePath)) {
134
+ const data = fs.readJsonSync(this.config.cachePath);
135
+ if (this.config.debug) {
136
+ console.log(`[CommandDeduplicator] 📂 Loaded cache: ${data.invocations.length} invocations`);
137
+ }
138
+ return data;
139
+ }
140
+ }
141
+ catch (error) {
142
+ if (this.config.debug) {
143
+ console.log(`[CommandDeduplicator] ⚠️ Failed to load cache: ${error}`);
144
+ }
145
+ }
146
+ // Return empty cache
147
+ return {
148
+ invocations: [],
149
+ lastCleanup: Date.now(),
150
+ totalInvocations: 0,
151
+ totalDuplicatesBlocked: 0
152
+ };
153
+ }
154
+ /**
155
+ * Save cache to disk
156
+ */
157
+ async saveCache() {
158
+ try {
159
+ await fs.ensureDir(path.dirname(this.config.cachePath));
160
+ await fs.writeJson(this.config.cachePath, this.cache, { spaces: 2 });
161
+ if (this.config.debug) {
162
+ console.log(`[CommandDeduplicator] 💾 Saved cache: ${this.cache.invocations.length} invocations`);
163
+ }
164
+ }
165
+ catch (error) {
166
+ console.error(`[CommandDeduplicator] ❌ Failed to save cache: ${error}`);
167
+ }
168
+ }
169
+ /**
170
+ * Clean up old invocation records
171
+ *
172
+ * Removes records older than 10x the deduplication window to prevent cache bloat.
173
+ */
174
+ async cleanup() {
175
+ const now = Date.now();
176
+ const cutoff = now - (this.config.windowMs * 10); // Keep 10x window
177
+ const before = this.cache.invocations.length;
178
+ this.cache.invocations = this.cache.invocations.filter(inv => inv.timestamp >= cutoff);
179
+ const after = this.cache.invocations.length;
180
+ // Also enforce max cache size
181
+ if (this.cache.invocations.length > this.config.maxCacheSize) {
182
+ this.cache.invocations = this.cache.invocations.slice(-this.config.maxCacheSize);
183
+ }
184
+ this.cache.lastCleanup = now;
185
+ if (this.config.debug && before > after) {
186
+ console.log(`[CommandDeduplicator] 🧹 Cleanup: Removed ${before - after} old records`);
187
+ }
188
+ await this.saveCache();
189
+ }
190
+ /**
191
+ * Get statistics about deduplication
192
+ *
193
+ * @returns Statistics object
194
+ */
195
+ getStats() {
196
+ return {
197
+ totalInvocations: this.cache.totalInvocations,
198
+ totalDuplicatesBlocked: this.cache.totalDuplicatesBlocked,
199
+ currentCacheSize: this.cache.invocations.length,
200
+ lastCleanup: new Date(this.cache.lastCleanup).toISOString()
201
+ };
202
+ }
203
+ /**
204
+ * Clear all cached invocations (useful for testing)
205
+ */
206
+ async clear() {
207
+ this.cache = {
208
+ invocations: [],
209
+ lastCleanup: Date.now(),
210
+ totalInvocations: 0,
211
+ totalDuplicatesBlocked: 0
212
+ };
213
+ await this.saveCache();
214
+ if (this.config.debug) {
215
+ console.log(`[CommandDeduplicator] 🗑️ Cache cleared`);
216
+ }
217
+ }
218
+ }
219
+ /**
220
+ * Global singleton instance (convenience)
221
+ */
222
+ let globalInstance = null;
223
+ /**
224
+ * Get global deduplicator instance
225
+ *
226
+ * @param config - Configuration (only used on first call)
227
+ * @returns Global deduplicator instance
228
+ */
229
+ export function getGlobalDeduplicator(config) {
230
+ if (!globalInstance) {
231
+ globalInstance = new CommandDeduplicator(config);
232
+ }
233
+ return globalInstance;
234
+ }
235
+ /**
236
+ * Convenience function: Check if command is duplicate
237
+ *
238
+ * @param command - Command name
239
+ * @param args - Command arguments
240
+ * @returns true if duplicate, false otherwise
241
+ */
242
+ export async function isDuplicate(command, args = []) {
243
+ return await getGlobalDeduplicator().checkDuplicate(command, args);
244
+ }
245
+ /**
246
+ * Convenience function: Record command invocation
247
+ *
248
+ * @param command - Command name
249
+ * @param args - Command arguments
250
+ */
251
+ export async function recordCommand(command, args = []) {
252
+ await getGlobalDeduplicator().recordInvocation(command, args);
253
+ }
254
+ //# sourceMappingURL=command-deduplicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-deduplicator.js","sourceRoot":"","sources":["../../../../src/core/deduplication/command-deduplicator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * SpecWeave Hierarchy Mapper
3
+ *
4
+ * Maps increments to Feature Spec (FS-*) folders following Universal Hierarchy architecture.
5
+ *
6
+ * Supports three complexity levels:
7
+ * 1. Simple: Increment → Issue/Epic/Feature (flat)
8
+ * 2. Standard: FS-* (Epic) → US-* (User Stories) → T-* (Tasks)
9
+ * 3. Enterprise: Domain → FS-* (Epic) → US-* → T-*
10
+ *
11
+ * @author SpecWeave Team
12
+ * @version 3.0.0
13
+ */
14
+ export interface HierarchyConfig {
15
+ level: 'simple' | 'standard' | 'enterprise' | 'auto';
16
+ specsBaseDir: string;
17
+ projectId: string;
18
+ featureFolderPattern: '{name}';
19
+ userStoriesSubdir: string;
20
+ detectFeatureFrom: ('frontmatter' | 'increment-name' | 'config')[];
21
+ fallbackFeature?: string;
22
+ }
23
+ export interface FeatureMapping {
24
+ featureId: string;
25
+ featureFolder: string;
26
+ featurePath: string;
27
+ userStoriesPath: string;
28
+ confidence: number;
29
+ detectionMethod: 'frontmatter' | 'increment-name' | 'config' | 'fallback';
30
+ }
31
+ export type EpicMapping = FeatureMapping;
32
+ /**
33
+ * HierarchyMapper - Maps increments to feature folders (named by concept, not increment number)
34
+ *
35
+ * NEW ARCHITECTURE (v0.18.0+):
36
+ * - Features are PERMANENT (named by concept: "release-management", "external-tool-sync")
37
+ * - Increments are TEMPORARY (named by execution: "0023-release-management-enhancements")
38
+ * - Multiple increments can contribute to same feature
39
+ * - No FS-### prefix (features aren't numbered)
40
+ */
41
+ export declare class HierarchyMapper {
42
+ private config;
43
+ private projectRoot;
44
+ constructor(projectRoot: string, config?: Partial<HierarchyConfig>);
45
+ /**
46
+ * Detect which feature folder this increment belongs to
47
+ *
48
+ * NEW: Features are named by CONCEPT (release-management), not INCREMENT NUMBER (FS-023)
49
+ */
50
+ detectFeatureMapping(incrementId: string): Promise<FeatureMapping>;
51
+ /**
52
+ * Legacy alias for backward compatibility
53
+ */
54
+ detectEpicMapping(incrementId: string): Promise<EpicMapping>;
55
+ /**
56
+ * Detect feature from frontmatter (epic: feature-name)
57
+ *
58
+ * FORMAT (v0.18.1+): Accepts simple feature names (external-tool-status-sync)
59
+ * LEGACY: Also accepts old FS-### format (FS-001) - extracts from increment name instead
60
+ */
61
+ private detectFromFrontmatter;
62
+ /**
63
+ * Detect feature from increment NAME
64
+ *
65
+ * FORMAT (v0.18.1+): Simple descriptive names (no date prefixes)
66
+ *
67
+ * Extracts the descriptive part of increment ID and normalizes it to feature name
68
+ * Examples:
69
+ * 0023-release-management-enhancements → release-management (new or existing)
70
+ * 0031-external-tool-status-sync → external-tool-status-sync
71
+ */
72
+ private detectFromIncrementName;
73
+ /**
74
+ * Detect feature from config mapping (explicit increment → feature mapping)
75
+ */
76
+ private detectFromConfig;
77
+ /**
78
+ * Create fallback mapping (extract feature name from increment ID)
79
+ *
80
+ * FORMAT (v0.18.1+): Simple descriptive names (no prefixes)
81
+ * - Uses core feature name extracted from increment ID
82
+ * - No date prefixes (removed to prevent duplicates)
83
+ * - No FS- prefixes (features are not numbered)
84
+ *
85
+ * Example: 0023-release-management-enhancements → release-management
86
+ */
87
+ private createFallbackMapping;
88
+ /**
89
+ * Get increment creation date in yy-mm-dd format
90
+ * Tries: metadata.json → spec.md frontmatter → current date
91
+ */
92
+ private getIncrementCreationDate;
93
+ /**
94
+ * Format date as yy-mm-dd
95
+ * Input: "2025-11-14" or "2025-11-14T12:00:00Z"
96
+ * Output: "25-11-14"
97
+ */
98
+ private formatDateShort;
99
+ /**
100
+ * NEW: Find feature folder by name (exact match or fuzzy match)
101
+ *
102
+ * Examples:
103
+ * release-management → release-management/
104
+ * external-tool-sync → external-tool-status-sync/ (fuzzy match)
105
+ */
106
+ private findFeatureFolder;
107
+ /**
108
+ * LEGACY: Find FS-* epic folder (for backward compatibility)
109
+ */
110
+ private findEpicFolder;
111
+ /**
112
+ * Get all feature folders (NEW: no FS- prefix filtering)
113
+ */
114
+ getAllFeatureFolders(): Promise<string[]>;
115
+ /**
116
+ * LEGACY: Get all epic folders (for backward compatibility)
117
+ */
118
+ getAllEpicFolders(): Promise<string[]>;
119
+ /**
120
+ * Validate feature folder structure (NEW: checks for FEATURE.md)
121
+ */
122
+ validateFeatureFolder(featureFolder: string): Promise<{
123
+ valid: boolean;
124
+ missing: string[];
125
+ }>;
126
+ /**
127
+ * LEGACY: Validate epic folder structure (for backward compatibility)
128
+ */
129
+ validateEpicFolder(epicFolder: string): Promise<{
130
+ valid: boolean;
131
+ missing: string[];
132
+ }>;
133
+ /**
134
+ * Create feature folder structure if missing (NEW: creates FEATURE.md)
135
+ */
136
+ createFeatureFolderStructure(featureFolder: string, title: string): Promise<void>;
137
+ /**
138
+ * LEGACY: Create epic folder structure (for backward compatibility)
139
+ */
140
+ createEpicFolderStructure(epicFolder: string, title: string): Promise<void>;
141
+ }
142
+ //# sourceMappingURL=hierarchy-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hierarchy-mapper.d.ts","sourceRoot":"","sources":["../../../../src/core/living-docs/hierarchy-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IACrD,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB,EAAE,QAAQ,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iBAAiB,EAAE,CAAC,aAAa,GAAG,gBAAgB,GAAG,QAAQ,CAAC,EAAE,CAAC;IACnE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,aAAa,GAAG,gBAAgB,GAAG,QAAQ,GAAG,UAAU,CAAC;CAC3E;AAGD,MAAM,MAAM,WAAW,GAAG,cAAc,CAAC;AAEzC;;;;;;;;GAQG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,WAAW,CAAS;gBAEhB,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC;IAelE;;;;OAIG;IACG,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAkCxE;;OAEG;IACG,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAIlE;;;;;OAKG;YACW,qBAAqB;IAuCnC;;;;;;;;;OASG;YACW,uBAAuB;IA0CrC;;OAEG;YACW,gBAAgB;IA+B9B;;;;;;;;;OASG;YACW,qBAAqB;IAqCnC;;;OAGG;YACW,wBAAwB;IAoCtC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAQvB;;;;;;OAMG;YACW,iBAAiB;IA8B/B;;OAEG;YACW,cAAc;IAI5B;;OAEG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IA0B/C;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAI5C;;OAEG;IACG,qBAAqB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAiBlG;;OAEG;IACG,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAI5F;;OAEG;IACG,4BAA4B,CAAC,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqEvF;;OAEG;IACG,yBAAyB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGlF"}