@lumenflow/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +119 -0
  3. package/dist/active-wu-detector.d.ts +33 -0
  4. package/dist/active-wu-detector.js +106 -0
  5. package/dist/adapters/filesystem-metrics.adapter.d.ts +108 -0
  6. package/dist/adapters/filesystem-metrics.adapter.js +519 -0
  7. package/dist/adapters/terminal-renderer.adapter.d.ts +106 -0
  8. package/dist/adapters/terminal-renderer.adapter.js +337 -0
  9. package/dist/arg-parser.d.ts +63 -0
  10. package/dist/arg-parser.js +560 -0
  11. package/dist/backlog-editor.d.ts +98 -0
  12. package/dist/backlog-editor.js +179 -0
  13. package/dist/backlog-generator.d.ts +111 -0
  14. package/dist/backlog-generator.js +381 -0
  15. package/dist/backlog-parser.d.ts +45 -0
  16. package/dist/backlog-parser.js +102 -0
  17. package/dist/backlog-sync-validator.d.ts +78 -0
  18. package/dist/backlog-sync-validator.js +294 -0
  19. package/dist/branch-drift.d.ts +34 -0
  20. package/dist/branch-drift.js +51 -0
  21. package/dist/cleanup-install-config.d.ts +33 -0
  22. package/dist/cleanup-install-config.js +37 -0
  23. package/dist/cleanup-lock.d.ts +139 -0
  24. package/dist/cleanup-lock.js +313 -0
  25. package/dist/code-path-validator.d.ts +146 -0
  26. package/dist/code-path-validator.js +537 -0
  27. package/dist/code-paths-overlap.d.ts +55 -0
  28. package/dist/code-paths-overlap.js +245 -0
  29. package/dist/commands-logger.d.ts +77 -0
  30. package/dist/commands-logger.js +254 -0
  31. package/dist/commit-message-utils.d.ts +25 -0
  32. package/dist/commit-message-utils.js +41 -0
  33. package/dist/compliance-parser.d.ts +150 -0
  34. package/dist/compliance-parser.js +507 -0
  35. package/dist/constants/backlog-patterns.d.ts +20 -0
  36. package/dist/constants/backlog-patterns.js +23 -0
  37. package/dist/constants/dora-constants.d.ts +49 -0
  38. package/dist/constants/dora-constants.js +53 -0
  39. package/dist/constants/gate-constants.d.ts +15 -0
  40. package/dist/constants/gate-constants.js +15 -0
  41. package/dist/constants/linter-constants.d.ts +16 -0
  42. package/dist/constants/linter-constants.js +16 -0
  43. package/dist/constants/tokenizer-constants.d.ts +15 -0
  44. package/dist/constants/tokenizer-constants.js +15 -0
  45. package/dist/core/scope-checker.d.ts +97 -0
  46. package/dist/core/scope-checker.js +163 -0
  47. package/dist/core/tool-runner.d.ts +161 -0
  48. package/dist/core/tool-runner.js +393 -0
  49. package/dist/core/tool.constants.d.ts +105 -0
  50. package/dist/core/tool.constants.js +101 -0
  51. package/dist/core/tool.schemas.d.ts +226 -0
  52. package/dist/core/tool.schemas.js +226 -0
  53. package/dist/core/worktree-guard.d.ts +130 -0
  54. package/dist/core/worktree-guard.js +242 -0
  55. package/dist/coverage-gate.d.ts +108 -0
  56. package/dist/coverage-gate.js +196 -0
  57. package/dist/date-utils.d.ts +75 -0
  58. package/dist/date-utils.js +140 -0
  59. package/dist/dependency-graph.d.ts +142 -0
  60. package/dist/dependency-graph.js +550 -0
  61. package/dist/dependency-guard.d.ts +54 -0
  62. package/dist/dependency-guard.js +142 -0
  63. package/dist/dependency-validator.d.ts +105 -0
  64. package/dist/dependency-validator.js +154 -0
  65. package/dist/docs-path-validator.d.ts +36 -0
  66. package/dist/docs-path-validator.js +95 -0
  67. package/dist/domain/orchestration.constants.d.ts +99 -0
  68. package/dist/domain/orchestration.constants.js +97 -0
  69. package/dist/domain/orchestration.schemas.d.ts +280 -0
  70. package/dist/domain/orchestration.schemas.js +211 -0
  71. package/dist/domain/orchestration.types.d.ts +133 -0
  72. package/dist/domain/orchestration.types.js +12 -0
  73. package/dist/error-handler.d.ts +116 -0
  74. package/dist/error-handler.js +136 -0
  75. package/dist/file-classifiers.d.ts +62 -0
  76. package/dist/file-classifiers.js +108 -0
  77. package/dist/gates-agent-mode.d.ts +81 -0
  78. package/dist/gates-agent-mode.js +94 -0
  79. package/dist/generate-traceability.d.ts +107 -0
  80. package/dist/generate-traceability.js +411 -0
  81. package/dist/git-adapter.d.ts +395 -0
  82. package/dist/git-adapter.js +649 -0
  83. package/dist/git-staged-validator.d.ts +32 -0
  84. package/dist/git-staged-validator.js +48 -0
  85. package/dist/hardcoded-strings.d.ts +61 -0
  86. package/dist/hardcoded-strings.js +270 -0
  87. package/dist/incremental-lint.d.ts +78 -0
  88. package/dist/incremental-lint.js +129 -0
  89. package/dist/incremental-test.d.ts +39 -0
  90. package/dist/incremental-test.js +61 -0
  91. package/dist/index.d.ts +42 -0
  92. package/dist/index.js +61 -0
  93. package/dist/invariants/check-automated-tests.d.ts +50 -0
  94. package/dist/invariants/check-automated-tests.js +166 -0
  95. package/dist/invariants-runner.d.ts +103 -0
  96. package/dist/invariants-runner.js +527 -0
  97. package/dist/lane-checker.d.ts +50 -0
  98. package/dist/lane-checker.js +319 -0
  99. package/dist/lane-inference.d.ts +39 -0
  100. package/dist/lane-inference.js +195 -0
  101. package/dist/lane-lock.d.ts +211 -0
  102. package/dist/lane-lock.js +474 -0
  103. package/dist/lane-validator.d.ts +48 -0
  104. package/dist/lane-validator.js +114 -0
  105. package/dist/logs-lib.d.ts +104 -0
  106. package/dist/logs-lib.js +207 -0
  107. package/dist/lumenflow-config-schema.d.ts +272 -0
  108. package/dist/lumenflow-config-schema.js +207 -0
  109. package/dist/lumenflow-config.d.ts +95 -0
  110. package/dist/lumenflow-config.js +236 -0
  111. package/dist/manual-test-validator.d.ts +80 -0
  112. package/dist/manual-test-validator.js +200 -0
  113. package/dist/merge-lock.d.ts +115 -0
  114. package/dist/merge-lock.js +251 -0
  115. package/dist/micro-worktree.d.ts +159 -0
  116. package/dist/micro-worktree.js +427 -0
  117. package/dist/migration-deployer.d.ts +69 -0
  118. package/dist/migration-deployer.js +151 -0
  119. package/dist/orchestration-advisory-loader.d.ts +28 -0
  120. package/dist/orchestration-advisory-loader.js +87 -0
  121. package/dist/orchestration-advisory.d.ts +58 -0
  122. package/dist/orchestration-advisory.js +94 -0
  123. package/dist/orchestration-di.d.ts +48 -0
  124. package/dist/orchestration-di.js +57 -0
  125. package/dist/orchestration-rules.d.ts +57 -0
  126. package/dist/orchestration-rules.js +201 -0
  127. package/dist/orphan-detector.d.ts +131 -0
  128. package/dist/orphan-detector.js +226 -0
  129. package/dist/path-classifiers.d.ts +57 -0
  130. package/dist/path-classifiers.js +93 -0
  131. package/dist/piped-command-detector.d.ts +34 -0
  132. package/dist/piped-command-detector.js +64 -0
  133. package/dist/ports/dashboard-renderer.port.d.ts +112 -0
  134. package/dist/ports/dashboard-renderer.port.js +25 -0
  135. package/dist/ports/metrics-collector.port.d.ts +132 -0
  136. package/dist/ports/metrics-collector.port.js +26 -0
  137. package/dist/process-detector.d.ts +84 -0
  138. package/dist/process-detector.js +172 -0
  139. package/dist/prompt-linter.d.ts +72 -0
  140. package/dist/prompt-linter.js +312 -0
  141. package/dist/prompt-monitor.d.ts +15 -0
  142. package/dist/prompt-monitor.js +205 -0
  143. package/dist/rebase-artifact-cleanup.d.ts +145 -0
  144. package/dist/rebase-artifact-cleanup.js +433 -0
  145. package/dist/retry-strategy.d.ts +189 -0
  146. package/dist/retry-strategy.js +283 -0
  147. package/dist/risk-detector.d.ts +108 -0
  148. package/dist/risk-detector.js +252 -0
  149. package/dist/rollback-utils.d.ts +76 -0
  150. package/dist/rollback-utils.js +104 -0
  151. package/dist/section-headings.d.ts +43 -0
  152. package/dist/section-headings.js +49 -0
  153. package/dist/spawn-escalation.d.ts +90 -0
  154. package/dist/spawn-escalation.js +253 -0
  155. package/dist/spawn-monitor.d.ts +229 -0
  156. package/dist/spawn-monitor.js +672 -0
  157. package/dist/spawn-recovery.d.ts +82 -0
  158. package/dist/spawn-recovery.js +298 -0
  159. package/dist/spawn-registry-schema.d.ts +98 -0
  160. package/dist/spawn-registry-schema.js +108 -0
  161. package/dist/spawn-registry-store.d.ts +146 -0
  162. package/dist/spawn-registry-store.js +273 -0
  163. package/dist/spawn-tree.d.ts +121 -0
  164. package/dist/spawn-tree.js +285 -0
  165. package/dist/stamp-status-validator.d.ts +84 -0
  166. package/dist/stamp-status-validator.js +134 -0
  167. package/dist/stamp-utils.d.ts +100 -0
  168. package/dist/stamp-utils.js +229 -0
  169. package/dist/state-machine.d.ts +26 -0
  170. package/dist/state-machine.js +83 -0
  171. package/dist/system-map-validator.d.ts +80 -0
  172. package/dist/system-map-validator.js +272 -0
  173. package/dist/telemetry.d.ts +80 -0
  174. package/dist/telemetry.js +213 -0
  175. package/dist/token-counter.d.ts +51 -0
  176. package/dist/token-counter.js +145 -0
  177. package/dist/usecases/get-dashboard-data.usecase.d.ts +52 -0
  178. package/dist/usecases/get-dashboard-data.usecase.js +61 -0
  179. package/dist/usecases/get-suggestions.usecase.d.ts +100 -0
  180. package/dist/usecases/get-suggestions.usecase.js +153 -0
  181. package/dist/user-normalizer.d.ts +41 -0
  182. package/dist/user-normalizer.js +141 -0
  183. package/dist/validators/phi-constants.d.ts +97 -0
  184. package/dist/validators/phi-constants.js +152 -0
  185. package/dist/validators/phi-scanner.d.ts +58 -0
  186. package/dist/validators/phi-scanner.js +215 -0
  187. package/dist/worktree-ownership.d.ts +50 -0
  188. package/dist/worktree-ownership.js +74 -0
  189. package/dist/worktree-scanner.d.ts +103 -0
  190. package/dist/worktree-scanner.js +168 -0
  191. package/dist/worktree-symlink.d.ts +99 -0
  192. package/dist/worktree-symlink.js +359 -0
  193. package/dist/wu-backlog-updater.d.ts +17 -0
  194. package/dist/wu-backlog-updater.js +37 -0
  195. package/dist/wu-checkpoint.d.ts +124 -0
  196. package/dist/wu-checkpoint.js +233 -0
  197. package/dist/wu-claim-helpers.d.ts +26 -0
  198. package/dist/wu-claim-helpers.js +63 -0
  199. package/dist/wu-claim-resume.d.ts +106 -0
  200. package/dist/wu-claim-resume.js +276 -0
  201. package/dist/wu-consistency-checker.d.ts +95 -0
  202. package/dist/wu-consistency-checker.js +567 -0
  203. package/dist/wu-constants.d.ts +1275 -0
  204. package/dist/wu-constants.js +1382 -0
  205. package/dist/wu-create-validators.d.ts +42 -0
  206. package/dist/wu-create-validators.js +93 -0
  207. package/dist/wu-done-branch-only.d.ts +63 -0
  208. package/dist/wu-done-branch-only.js +191 -0
  209. package/dist/wu-done-messages.d.ts +119 -0
  210. package/dist/wu-done-messages.js +185 -0
  211. package/dist/wu-done-pr.d.ts +72 -0
  212. package/dist/wu-done-pr.js +174 -0
  213. package/dist/wu-done-retry-helpers.d.ts +85 -0
  214. package/dist/wu-done-retry-helpers.js +172 -0
  215. package/dist/wu-done-ui.d.ts +37 -0
  216. package/dist/wu-done-ui.js +69 -0
  217. package/dist/wu-done-validators.d.ts +411 -0
  218. package/dist/wu-done-validators.js +1229 -0
  219. package/dist/wu-done-worktree.d.ts +182 -0
  220. package/dist/wu-done-worktree.js +1097 -0
  221. package/dist/wu-helpers.d.ts +128 -0
  222. package/dist/wu-helpers.js +248 -0
  223. package/dist/wu-lint.d.ts +70 -0
  224. package/dist/wu-lint.js +234 -0
  225. package/dist/wu-paths.d.ts +171 -0
  226. package/dist/wu-paths.js +178 -0
  227. package/dist/wu-preflight-validators.d.ts +86 -0
  228. package/dist/wu-preflight-validators.js +251 -0
  229. package/dist/wu-recovery.d.ts +138 -0
  230. package/dist/wu-recovery.js +341 -0
  231. package/dist/wu-repair-core.d.ts +131 -0
  232. package/dist/wu-repair-core.js +669 -0
  233. package/dist/wu-schema-normalization.d.ts +17 -0
  234. package/dist/wu-schema-normalization.js +82 -0
  235. package/dist/wu-schema.d.ts +793 -0
  236. package/dist/wu-schema.js +881 -0
  237. package/dist/wu-spawn-helpers.d.ts +121 -0
  238. package/dist/wu-spawn-helpers.js +271 -0
  239. package/dist/wu-spawn.d.ts +158 -0
  240. package/dist/wu-spawn.js +1306 -0
  241. package/dist/wu-state-schema.d.ts +213 -0
  242. package/dist/wu-state-schema.js +156 -0
  243. package/dist/wu-state-store.d.ts +264 -0
  244. package/dist/wu-state-store.js +691 -0
  245. package/dist/wu-status-transition.d.ts +63 -0
  246. package/dist/wu-status-transition.js +382 -0
  247. package/dist/wu-status-updater.d.ts +25 -0
  248. package/dist/wu-status-updater.js +116 -0
  249. package/dist/wu-transaction-collectors.d.ts +116 -0
  250. package/dist/wu-transaction-collectors.js +272 -0
  251. package/dist/wu-transaction.d.ts +170 -0
  252. package/dist/wu-transaction.js +273 -0
  253. package/dist/wu-validation-constants.d.ts +60 -0
  254. package/dist/wu-validation-constants.js +66 -0
  255. package/dist/wu-validation.d.ts +118 -0
  256. package/dist/wu-validation.js +243 -0
  257. package/dist/wu-validator.d.ts +62 -0
  258. package/dist/wu-validator.js +325 -0
  259. package/dist/wu-yaml-fixer.d.ts +97 -0
  260. package/dist/wu-yaml-fixer.js +264 -0
  261. package/dist/wu-yaml.d.ts +86 -0
  262. package/dist/wu-yaml.js +222 -0
  263. package/package.json +114 -0
@@ -0,0 +1,236 @@
1
+ /**
2
+ * LumenFlow Configuration Loader
3
+ *
4
+ * Loads and manages LumenFlow configuration from .lumenflow.config.yaml
5
+ * Falls back to sensible defaults if no config file exists.
6
+ *
7
+ * @module lumenflow-config
8
+ */
9
+ import * as fs from 'node:fs';
10
+ import * as path from 'node:path';
11
+ import * as yaml from 'yaml';
12
+ import { parseConfig, getDefaultConfig, validateConfig, } from './lumenflow-config-schema.js';
13
+ /** Default config file name */
14
+ const CONFIG_FILE_NAME = '.lumenflow.config.yaml';
15
+ /** Cached config instance */
16
+ let cachedConfig = null;
17
+ /** Cached project root */
18
+ let cachedProjectRoot = null;
19
+ /**
20
+ * Find project root by looking for .lumenflow.config.yaml or .git
21
+ *
22
+ * @param startDir - Directory to start searching from
23
+ * @returns Project root path or current working directory
24
+ */
25
+ export function findProjectRoot(startDir = process.cwd()) {
26
+ let currentDir = path.resolve(startDir);
27
+ const root = path.parse(currentDir).root;
28
+ while (currentDir !== root) {
29
+ // Check for config file first
30
+ if (fs.existsSync(path.join(currentDir, CONFIG_FILE_NAME))) {
31
+ return currentDir;
32
+ }
33
+ // Fall back to .git directory
34
+ if (fs.existsSync(path.join(currentDir, '.git'))) {
35
+ return currentDir;
36
+ }
37
+ currentDir = path.dirname(currentDir);
38
+ }
39
+ return process.cwd();
40
+ }
41
+ /**
42
+ * Load configuration from file
43
+ *
44
+ * @param projectRoot - Project root directory
45
+ * @returns Parsed configuration or null if file doesn't exist
46
+ */
47
+ function loadConfigFile(projectRoot) {
48
+ const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
49
+ if (!fs.existsSync(configPath)) {
50
+ return null;
51
+ }
52
+ try {
53
+ const content = fs.readFileSync(configPath, 'utf8');
54
+ const data = yaml.parse(content);
55
+ return data || {};
56
+ }
57
+ catch (error) {
58
+ console.warn(`Warning: Failed to parse ${CONFIG_FILE_NAME}:`, error);
59
+ return null;
60
+ }
61
+ }
62
+ /**
63
+ * Get LumenFlow configuration
64
+ *
65
+ * Loads config from .lumenflow.config.yaml if present, otherwise uses defaults.
66
+ * Configuration is cached for performance.
67
+ *
68
+ * @param options - Options for loading config
69
+ * @param options.projectRoot - Override project root detection
70
+ * @param options.reload - Force reload from disk (bypass cache)
71
+ * @returns LumenFlow configuration
72
+ */
73
+ export function getConfig(options = {}) {
74
+ const { projectRoot: overrideRoot, reload = false } = options;
75
+ // Use cached config if available and not reloading
76
+ if (cachedConfig && !reload && !overrideRoot) {
77
+ return cachedConfig;
78
+ }
79
+ // Find or use provided project root
80
+ const projectRoot = overrideRoot || findProjectRoot();
81
+ // Load config file if exists
82
+ const fileConfig = loadConfigFile(projectRoot);
83
+ // Parse with defaults
84
+ const config = parseConfig(fileConfig || {});
85
+ // Cache if using default project root
86
+ if (!overrideRoot) {
87
+ cachedConfig = config;
88
+ cachedProjectRoot = projectRoot;
89
+ }
90
+ return config;
91
+ }
92
+ /**
93
+ * Get the project root directory
94
+ *
95
+ * @returns Cached project root or finds it
96
+ */
97
+ export function getProjectRoot() {
98
+ if (cachedProjectRoot) {
99
+ return cachedProjectRoot;
100
+ }
101
+ cachedProjectRoot = findProjectRoot();
102
+ return cachedProjectRoot;
103
+ }
104
+ /**
105
+ * Clear cached configuration
106
+ *
107
+ * Useful for testing or when config file changes
108
+ */
109
+ export function clearConfigCache() {
110
+ cachedConfig = null;
111
+ cachedProjectRoot = null;
112
+ }
113
+ /**
114
+ * Resolve a path relative to project root
115
+ *
116
+ * @param relativePath - Relative path from config
117
+ * @param projectRoot - Optional project root override
118
+ * @returns Absolute path
119
+ */
120
+ export function resolvePath(relativePath, projectRoot) {
121
+ const root = projectRoot || getProjectRoot();
122
+ return path.join(root, relativePath);
123
+ }
124
+ /**
125
+ * Get resolved paths for common directories
126
+ *
127
+ * Convenience function that resolves all directory paths to absolute paths
128
+ *
129
+ * @param options - Options
130
+ * @param options.projectRoot - Override project root
131
+ * @returns Object with absolute paths
132
+ */
133
+ export function getResolvedPaths(options = {}) {
134
+ const projectRoot = options.projectRoot || getProjectRoot();
135
+ const config = getConfig({ projectRoot });
136
+ return {
137
+ wuDir: path.join(projectRoot, config.directories.wuDir),
138
+ initiativesDir: path.join(projectRoot, config.directories.initiativesDir),
139
+ backlogPath: path.join(projectRoot, config.directories.backlogPath),
140
+ statusPath: path.join(projectRoot, config.directories.statusPath),
141
+ worktrees: path.join(projectRoot, config.directories.worktrees),
142
+ stampsDir: path.join(projectRoot, config.beacon.stampsDir),
143
+ stateDir: path.join(projectRoot, config.beacon.stateDir),
144
+ skillsDir: path.join(projectRoot, config.directories.skillsDir),
145
+ agentsDir: path.join(projectRoot, config.directories.agentsDir),
146
+ memoryBank: path.join(projectRoot, config.directories.memoryBank),
147
+ };
148
+ }
149
+ /**
150
+ * Validate a config file
151
+ *
152
+ * @param configPath - Path to config file
153
+ * @returns Validation result
154
+ */
155
+ export function validateConfigFile(configPath) {
156
+ if (!fs.existsSync(configPath)) {
157
+ return { valid: false, errors: ['Config file not found'] };
158
+ }
159
+ try {
160
+ const content = fs.readFileSync(configPath, 'utf8');
161
+ const data = yaml.parse(content);
162
+ const result = validateConfig(data);
163
+ if (result.success) {
164
+ return { valid: true, errors: [], config: result.data };
165
+ }
166
+ const errors = result.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`);
167
+ return { valid: false, errors };
168
+ }
169
+ catch (error) {
170
+ return {
171
+ valid: false,
172
+ errors: [`Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`],
173
+ };
174
+ }
175
+ }
176
+ /**
177
+ * Create a sample config file
178
+ *
179
+ * @param outputPath - Path to write config file
180
+ * @param options - Options for sample config
181
+ */
182
+ export function createSampleConfig(outputPath, options = {}) {
183
+ const { includeComments = true } = options;
184
+ const defaultConfig = getDefaultConfig();
185
+ const configContent = includeComments
186
+ ? `# LumenFlow Configuration
187
+ # This file configures paths and settings for the LumenFlow workflow framework.
188
+ # All paths are relative to the project root.
189
+
190
+ version: "${defaultConfig.version}"
191
+
192
+ # Directory paths
193
+ directories:
194
+ # WU YAML files directory
195
+ wuDir: "${defaultConfig.directories.wuDir}"
196
+ # Initiatives directory
197
+ initiativesDir: "${defaultConfig.directories.initiativesDir}"
198
+ # Backlog file path
199
+ backlogPath: "${defaultConfig.directories.backlogPath}"
200
+ # Status file path
201
+ statusPath: "${defaultConfig.directories.statusPath}"
202
+ # Worktrees directory
203
+ worktrees: "${defaultConfig.directories.worktrees}"
204
+ # Skills directory
205
+ skillsDir: "${defaultConfig.directories.skillsDir}"
206
+ # Agents directory
207
+ agentsDir: "${defaultConfig.directories.agentsDir}"
208
+
209
+ # Beacon paths (.beacon directory structure)
210
+ beacon:
211
+ base: "${defaultConfig.beacon.base}"
212
+ stampsDir: "${defaultConfig.beacon.stampsDir}"
213
+ stateDir: "${defaultConfig.beacon.stateDir}"
214
+
215
+ # Git configuration
216
+ git:
217
+ mainBranch: "${defaultConfig.git.mainBranch}"
218
+ defaultRemote: "${defaultConfig.git.defaultRemote}"
219
+ maxBranchDrift: ${defaultConfig.git.maxBranchDrift}
220
+
221
+ # WU configuration
222
+ wu:
223
+ minDescriptionLength: ${defaultConfig.wu.minDescriptionLength}
224
+ maxCommitSubject: ${defaultConfig.wu.maxCommitSubject}
225
+ defaultPriority: "${defaultConfig.wu.defaultPriority}"
226
+ defaultStatus: "${defaultConfig.wu.defaultStatus}"
227
+
228
+ # Gates configuration
229
+ gates:
230
+ maxEslintWarnings: ${defaultConfig.gates.maxEslintWarnings}
231
+ enableCoverage: ${defaultConfig.gates.enableCoverage}
232
+ minCoverage: ${defaultConfig.gates.minCoverage}
233
+ `
234
+ : yaml.stringify(defaultConfig);
235
+ fs.writeFileSync(outputPath, configContent, 'utf8');
236
+ }
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Manual Test Escape Hatch Validator
4
+ *
5
+ * WU-1433: Restricts manual-only tests for WUs touching hex core code.
6
+ * WU-2332: Require automated tests for all code files, remove lane exemptions.
7
+ *
8
+ * Implementation WUs must have at least one automated test (unit/e2e/integration).
9
+ *
10
+ * Exemptions:
11
+ * - type: documentation only
12
+ * - code_paths containing only documentation/config files (no code files)
13
+ *
14
+ * @see {@link tools/lib/wu-done-validators.mjs} - Integration point
15
+ * @see {@link docs/04-operations/_frameworks/lumenflow/lumenflow-complete.md} - TDD requirements
16
+ */
17
+ /**
18
+ * Path prefixes for hex core code requiring automated tests.
19
+ * These are the critical application layer paths.
20
+ *
21
+ * @constant {string[]}
22
+ */
23
+ export declare const HEX_CORE_CODE_PATTERNS: readonly string[];
24
+ /**
25
+ * @deprecated Lane-based exemptions removed in WU-2332.
26
+ * Test requirements are now based on file types, not lanes.
27
+ * Kept for backward compatibility but no longer used.
28
+ * @constant {string[]}
29
+ */
30
+ export declare const EXEMPT_LANES: readonly any[];
31
+ /**
32
+ * WU types exempt from automated test requirement.
33
+ * Only 'documentation' type is exempt - actual code changes require automated tests.
34
+ *
35
+ * @constant {string[]}
36
+ */
37
+ export declare const EXEMPT_TYPES: readonly string[];
38
+ /**
39
+ * Determine if a file path represents a code file requiring automated tests.
40
+ *
41
+ * Code files are those with extensions like .mjs, .ts, .tsx, .js
42
+ * EXCEPT config files (vitest.config.ts, .eslintrc.js, etc.)
43
+ *
44
+ * @param {string} filePath - File path to check
45
+ * @returns {boolean} True if the file is a code file requiring tests
46
+ */
47
+ export declare function isCodeFile(filePath: any): boolean;
48
+ /**
49
+ * Check if code_paths contains any hex core code.
50
+ *
51
+ * @param {string[]|null|undefined} codePaths - Array of file paths from WU YAML
52
+ * @returns {boolean} True if any path is in hex core layer
53
+ */
54
+ export declare function containsHexCoreCode(codePaths: any): boolean;
55
+ /**
56
+ * Check if a WU is exempt from automated test requirement.
57
+ *
58
+ * WU-2332: Only type: 'documentation' is exempt.
59
+ * Lane-based exemptions have been removed - test requirements
60
+ * are now based on file types in code_paths.
61
+ *
62
+ * @param {object} doc - WU YAML document
63
+ * @returns {boolean} True if WU is exempt
64
+ */
65
+ export declare function isExemptFromAutomatedTests(doc: any): boolean;
66
+ /**
67
+ * Validate automated test requirement for WU.
68
+ *
69
+ * WU-2332: Requirements are based on file types, not lanes.
70
+ * - WUs with ANY code files in code_paths must have automated tests
71
+ * - WUs with only docs/config files can use manual-only tests
72
+ * - type: 'documentation' is always exempt
73
+ *
74
+ * @param {object} doc - WU YAML document
75
+ * @returns {{ valid: boolean, errors: string[] }} Validation result
76
+ */
77
+ export declare function validateAutomatedTestRequirement(doc: any): {
78
+ valid: boolean;
79
+ errors: any[];
80
+ };
@@ -0,0 +1,200 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Manual Test Escape Hatch Validator
4
+ *
5
+ * WU-1433: Restricts manual-only tests for WUs touching hex core code.
6
+ * WU-2332: Require automated tests for all code files, remove lane exemptions.
7
+ *
8
+ * Implementation WUs must have at least one automated test (unit/e2e/integration).
9
+ *
10
+ * Exemptions:
11
+ * - type: documentation only
12
+ * - code_paths containing only documentation/config files (no code files)
13
+ *
14
+ * @see {@link tools/lib/wu-done-validators.mjs} - Integration point
15
+ * @see {@link docs/04-operations/_frameworks/lumenflow/lumenflow-complete.md} - TDD requirements
16
+ */
17
+ import path from 'node:path';
18
+ import { TEST_TYPES, WU_TYPES } from './wu-constants.js';
19
+ /**
20
+ * Code file extensions that require automated tests.
21
+ * @constant {string[]}
22
+ */
23
+ const CODE_EXTENSIONS = Object.freeze(['.js', '.ts', '.tsx', '.js']);
24
+ /**
25
+ * Non-code file extensions (documentation, data, config).
26
+ * @constant {string[]}
27
+ */
28
+ const NON_CODE_EXTENSIONS = Object.freeze(['.md', '.yaml', '.yml', '.json']);
29
+ /**
30
+ * Patterns that indicate a config file (even with code extensions).
31
+ * @constant {RegExp[]}
32
+ */
33
+ const CONFIG_PATTERNS = Object.freeze([
34
+ /config\./i, // vitest.config.ts, eslint.config.js
35
+ /\.config\./i, // *.config.ts, *.config.js
36
+ /rc\.[jt]s$/i, // .eslintrc.js, .prettierrc.ts
37
+ /^\.[a-z]+rc\./i, // .eslintrc.*, .prettierrc.*
38
+ ]);
39
+ /**
40
+ * Path prefixes for hex core code requiring automated tests.
41
+ * These are the critical application layer paths.
42
+ *
43
+ * @constant {string[]}
44
+ */
45
+ export const HEX_CORE_CODE_PATTERNS = Object.freeze([
46
+ 'packages/@patientpath/application/',
47
+ 'packages/@patientpath/prompts/',
48
+ 'packages/@patientpath/ports/',
49
+ ]);
50
+ /**
51
+ * @deprecated Lane-based exemptions removed in WU-2332.
52
+ * Test requirements are now based on file types, not lanes.
53
+ * Kept for backward compatibility but no longer used.
54
+ * @constant {string[]}
55
+ */
56
+ export const EXEMPT_LANES = Object.freeze([]);
57
+ /**
58
+ * WU types exempt from automated test requirement.
59
+ * Only 'documentation' type is exempt - actual code changes require automated tests.
60
+ *
61
+ * @constant {string[]}
62
+ */
63
+ export const EXEMPT_TYPES = Object.freeze([WU_TYPES.DOCUMENTATION]);
64
+ /**
65
+ * Determine if a file path represents a code file requiring automated tests.
66
+ *
67
+ * Code files are those with extensions like .mjs, .ts, .tsx, .js
68
+ * EXCEPT config files (vitest.config.ts, .eslintrc.js, etc.)
69
+ *
70
+ * @param {string} filePath - File path to check
71
+ * @returns {boolean} True if the file is a code file requiring tests
72
+ */
73
+ export function isCodeFile(filePath) {
74
+ if (!filePath || typeof filePath !== 'string') {
75
+ return false;
76
+ }
77
+ // Get the filename from the path
78
+ const fileName = path.basename(filePath);
79
+ const ext = path.extname(filePath).toLowerCase();
80
+ // Check if it's a non-code extension (docs, data)
81
+ if (NON_CODE_EXTENSIONS.includes(ext)) {
82
+ return false;
83
+ }
84
+ // Check if it's a code extension
85
+ if (!CODE_EXTENSIONS.includes(ext)) {
86
+ return false;
87
+ }
88
+ // Check if it's a config file (even with code extension)
89
+ const isConfig = CONFIG_PATTERNS.some((pattern) => pattern.test(fileName));
90
+ if (isConfig) {
91
+ return false;
92
+ }
93
+ return true;
94
+ }
95
+ /**
96
+ * Check if code_paths contains any hex core code.
97
+ *
98
+ * @param {string[]|null|undefined} codePaths - Array of file paths from WU YAML
99
+ * @returns {boolean} True if any path is in hex core layer
100
+ */
101
+ export function containsHexCoreCode(codePaths) {
102
+ if (!codePaths || !Array.isArray(codePaths) || codePaths.length === 0) {
103
+ return false;
104
+ }
105
+ return codePaths.some((path) => {
106
+ if (!path || typeof path !== 'string')
107
+ return false;
108
+ return HEX_CORE_CODE_PATTERNS.some((pattern) => path.startsWith(pattern));
109
+ });
110
+ }
111
+ /**
112
+ * Check if a WU is exempt from automated test requirement.
113
+ *
114
+ * WU-2332: Only type: 'documentation' is exempt.
115
+ * Lane-based exemptions have been removed - test requirements
116
+ * are now based on file types in code_paths.
117
+ *
118
+ * @param {object} doc - WU YAML document
119
+ * @returns {boolean} True if WU is exempt
120
+ */
121
+ export function isExemptFromAutomatedTests(doc) {
122
+ if (!doc)
123
+ return false;
124
+ // Only type: documentation is exempt
125
+ const type = doc.type || '';
126
+ if (typeof type === 'string' && EXEMPT_TYPES.includes(type)) {
127
+ return true;
128
+ }
129
+ return false;
130
+ }
131
+ /**
132
+ * Check if WU has at least one automated test.
133
+ *
134
+ * @param {object} tests - Tests object from WU YAML
135
+ * @returns {boolean} True if has at least one automated test
136
+ */
137
+ function hasAutomatedTest(tests) {
138
+ if (!tests)
139
+ return false;
140
+ const hasItems = (arr) => Array.isArray(arr) && arr.length > 0;
141
+ return (hasItems(tests[TEST_TYPES.UNIT]) ||
142
+ hasItems(tests[TEST_TYPES.E2E]) ||
143
+ hasItems(tests[TEST_TYPES.INTEGRATION]));
144
+ }
145
+ /**
146
+ * Check if any code_paths contain actual code files (not docs/config).
147
+ *
148
+ * @param {string[]} codePaths - Array of file paths from WU YAML
149
+ * @returns {{ hasCodeFiles: boolean, codeFiles: string[] }} Result with list of code files
150
+ */
151
+ function analyzeCodePaths(codePaths) {
152
+ if (!codePaths || !Array.isArray(codePaths) || codePaths.length === 0) {
153
+ return { hasCodeFiles: false, codeFiles: [] };
154
+ }
155
+ const codeFiles = codePaths.filter((p) => isCodeFile(p));
156
+ return {
157
+ hasCodeFiles: codeFiles.length > 0,
158
+ codeFiles,
159
+ };
160
+ }
161
+ /**
162
+ * Validate automated test requirement for WU.
163
+ *
164
+ * WU-2332: Requirements are based on file types, not lanes.
165
+ * - WUs with ANY code files in code_paths must have automated tests
166
+ * - WUs with only docs/config files can use manual-only tests
167
+ * - type: 'documentation' is always exempt
168
+ *
169
+ * @param {object} doc - WU YAML document
170
+ * @returns {{ valid: boolean, errors: string[] }} Validation result
171
+ */
172
+ export function validateAutomatedTestRequirement(doc) {
173
+ const errors = [];
174
+ if (!doc) {
175
+ return { valid: true, errors: [] };
176
+ }
177
+ // Check if WU is exempt by type
178
+ if (isExemptFromAutomatedTests(doc)) {
179
+ return { valid: true, errors: [] };
180
+ }
181
+ // Analyze code_paths for actual code files
182
+ const codePaths = doc.code_paths || [];
183
+ const { hasCodeFiles, codeFiles } = analyzeCodePaths(codePaths);
184
+ // If no code files, manual tests are fine
185
+ if (!hasCodeFiles) {
186
+ return { valid: true, errors: [] };
187
+ }
188
+ // WU has code files - require automated tests
189
+ // Support both tests: (current) and test_paths: (legacy)
190
+ const tests = doc.tests || doc.test_paths || {};
191
+ if (!hasAutomatedTest(tests)) {
192
+ errors.push(`WU modifies code files but has no automated tests.\n` +
193
+ ` Code files: ${codeFiles.join(', ')}\n` +
194
+ ` Required: At least one automated test (unit, e2e, or integration)\n` +
195
+ ` Manual-only tests are not allowed for code changes.\n\n` +
196
+ ` Fix: Add tests to tests.unit, tests.e2e, or tests.integration in WU YAML.`);
197
+ return { valid: false, errors };
198
+ }
199
+ return { valid: true, errors: [] };
200
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * WU-1747: Merge Lock Module
3
+ *
4
+ * Provides atomic locking mechanism for wu:done merge operations
5
+ * to prevent race conditions during concurrent completions.
6
+ *
7
+ * Features:
8
+ * - File-based lock with PID and timestamp
9
+ * - Stale lock detection and auto-cleanup
10
+ * - Idempotent re-acquisition for same WU
11
+ * - Guaranteed cleanup via withMergeLock wrapper
12
+ *
13
+ * @module merge-lock
14
+ */
15
+ /**
16
+ * Default timeout for waiting to acquire lock (ms)
17
+ * After this time, acquisition fails if lock is held
18
+ */
19
+ export declare const MERGE_LOCK_TIMEOUT_MS = 30000;
20
+ /**
21
+ * Time after which a lock is considered stale and can be forcibly released (ms)
22
+ * Should be greater than expected merge operation duration
23
+ */
24
+ export declare const MERGE_LOCK_STALE_MS = 60000;
25
+ /**
26
+ * @typedef {Object} LockInfo
27
+ * @property {string} wuId - WU ID that holds the lock
28
+ * @property {string} lockId - Unique lock identifier
29
+ * @property {string} createdAt - ISO timestamp when lock was created
30
+ * @property {number} pid - Process ID of lock holder
31
+ * @property {string} hostname - Hostname of lock holder
32
+ */
33
+ /**
34
+ * @typedef {Object} AcquireResult
35
+ * @property {boolean} acquired - Whether lock was acquired
36
+ * @property {string} [lockId] - Lock ID if acquired
37
+ * @property {string} [heldBy] - WU ID holding the lock if not acquired
38
+ * @property {string} [heldSince] - ISO timestamp if not acquired
39
+ */
40
+ /**
41
+ * Options for lock file operations
42
+ */
43
+ interface MergeLockBaseDirOptions {
44
+ /** Base directory (defaults to cwd) */
45
+ baseDir?: string;
46
+ }
47
+ /**
48
+ * Check if merge lock is currently held
49
+ *
50
+ * @param {MergeLockBaseDirOptions} [options]
51
+ * @returns {boolean} True if lock is held (and not stale)
52
+ */
53
+ export declare function isMergeLocked(options?: MergeLockBaseDirOptions): boolean;
54
+ /**
55
+ * Get information about current merge lock
56
+ *
57
+ * @param {MergeLockBaseDirOptions} [options]
58
+ * @returns {LockInfo|null} Lock info or null if unlocked
59
+ */
60
+ export declare function getMergeLockInfo(options?: MergeLockBaseDirOptions): any;
61
+ /**
62
+ * Options for acquiring merge lock
63
+ */
64
+ export interface AcquireMergeLockOptions extends MergeLockBaseDirOptions {
65
+ /** Max time to wait for lock (default: MERGE_LOCK_TIMEOUT_MS) */
66
+ waitMs?: number;
67
+ }
68
+ /**
69
+ * Attempt to acquire the merge lock
70
+ *
71
+ * Will wait up to waitMs for lock to become available.
72
+ * If the same WU already holds the lock, re-acquisition succeeds (idempotent).
73
+ * Stale locks are automatically cleaned up.
74
+ *
75
+ * @param {string} wuId - WU ID requesting the lock
76
+ * @param {AcquireMergeLockOptions} [options]
77
+ * @returns {Promise<AcquireResult>} Acquisition result
78
+ */
79
+ export declare function acquireMergeLock(wuId: any, options?: AcquireMergeLockOptions): Promise<{
80
+ acquired: boolean;
81
+ lockId: any;
82
+ heldBy?: undefined;
83
+ heldSince?: undefined;
84
+ } | {
85
+ acquired: boolean;
86
+ heldBy: any;
87
+ heldSince: any;
88
+ lockId?: undefined;
89
+ }>;
90
+ /**
91
+ * Release the merge lock
92
+ *
93
+ * Only releases if the provided lockId matches the current lock.
94
+ * This prevents accidentally releasing another WU's lock.
95
+ *
96
+ * @param {string} lockId - Lock ID to release
97
+ * @param {MergeLockBaseDirOptions} [options]
98
+ * @returns {boolean} True if lock was released
99
+ */
100
+ export declare function releaseMergeLock(lockId: any, options?: MergeLockBaseDirOptions): boolean;
101
+ /**
102
+ * Execute a function while holding the merge lock
103
+ *
104
+ * Guarantees the lock is released after function completes,
105
+ * even if the function throws an error.
106
+ *
107
+ * @template T
108
+ * @param {string} wuId - WU ID requesting the lock
109
+ * @param {function(): Promise<T>} fn - Async function to execute
110
+ * @param {AcquireMergeLockOptions} [options]
111
+ * @returns {Promise<T>} Result of function execution
112
+ * @throws {Error} If lock cannot be acquired or function throws
113
+ */
114
+ export declare function withMergeLock<T>(wuId: string, fn: () => Promise<T>, options?: AcquireMergeLockOptions): Promise<T>;
115
+ export {};