@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,273 @@
1
+ /**
2
+ * WU Transaction - Atomic write operations for wu:done
3
+ *
4
+ * WU-1369: Implements transactional pattern for metadata updates.
5
+ * Collects all changes in memory, validates, then writes atomically.
6
+ *
7
+ * Pattern:
8
+ * 1. Create transaction
9
+ * 2. Collect all pending writes (in memory)
10
+ * 3. Validate pending state
11
+ * 4. Commit (write all files) or abort (discard)
12
+ *
13
+ * This ensures no partial state on validation failure:
14
+ * - If validation fails → no files written
15
+ * - If any write fails → error with cleanup info
16
+ */
17
+ import { existsSync, writeFileSync, mkdirSync, readFileSync, unlinkSync } from 'node:fs';
18
+ import path from 'node:path';
19
+ import { LOG_PREFIX, EMOJI } from './wu-constants.js';
20
+ import { createError, ErrorCodes } from './error-handler.js';
21
+ /**
22
+ * Transaction for atomic metadata updates
23
+ *
24
+ * Usage:
25
+ * ```js
26
+ * const tx = new WUTransaction(id);
27
+ *
28
+ * // Collect pending changes
29
+ * tx.addWrite(wuPath, yamlContent, 'WU YAML');
30
+ * tx.addWrite(statusPath, statusContent, 'status.md');
31
+ *
32
+ * // Validate (no writes happen yet)
33
+ * const validation = tx.validate();
34
+ * if (!validation.valid) {
35
+ * tx.abort();
36
+ * return;
37
+ * }
38
+ *
39
+ * // Commit all changes atomically
40
+ * const result = tx.commit();
41
+ * ```
42
+ */
43
+ export class WUTransaction {
44
+ wuId;
45
+ pendingWrites;
46
+ committed;
47
+ aborted;
48
+ createdAt;
49
+ /**
50
+ * Create a new transaction
51
+ * @param {string} wuId - WU ID for logging context
52
+ */
53
+ constructor(wuId) {
54
+ this.wuId = wuId;
55
+ this.pendingWrites = new Map();
56
+ this.committed = false;
57
+ this.aborted = false;
58
+ this.createdAt = new Date();
59
+ }
60
+ /**
61
+ * Add a pending file write operation
62
+ *
63
+ * @param {string} filePath - File path to write
64
+ * @param {string} content - Content to write
65
+ * @param {string} description - Human-readable description
66
+ * @throws {Error} If transaction already committed or aborted
67
+ */
68
+ addWrite(filePath, content, description) {
69
+ if (this.committed) {
70
+ throw createError(ErrorCodes.TRANSACTION_ERROR, `Cannot add writes to committed transaction (${this.wuId})`, { wuId: this.wuId, path: filePath });
71
+ }
72
+ if (this.aborted) {
73
+ throw createError(ErrorCodes.TRANSACTION_ERROR, `Cannot add writes to aborted transaction (${this.wuId})`, { wuId: this.wuId, path: filePath });
74
+ }
75
+ this.pendingWrites.set(filePath, {
76
+ path: filePath,
77
+ content,
78
+ description,
79
+ });
80
+ }
81
+ /**
82
+ * Get pending writes for inspection
83
+ * @returns {PendingWrite[]}
84
+ */
85
+ getPendingWrites() {
86
+ return Array.from(this.pendingWrites.values());
87
+ }
88
+ /**
89
+ * Get count of pending writes
90
+ * @returns {number}
91
+ */
92
+ get size() {
93
+ return this.pendingWrites.size;
94
+ }
95
+ /**
96
+ * Check if transaction has been committed
97
+ * @returns {boolean}
98
+ */
99
+ get isCommitted() {
100
+ return this.committed;
101
+ }
102
+ /**
103
+ * Check if transaction has been aborted
104
+ * @returns {boolean}
105
+ */
106
+ get isAborted() {
107
+ return this.aborted;
108
+ }
109
+ /**
110
+ * Validate pending writes (pre-commit checks)
111
+ *
112
+ * Checks:
113
+ * - All parent directories can be created
114
+ * - No duplicate paths with different content
115
+ * - Content is valid (non-empty for critical files)
116
+ *
117
+ * @returns {{ valid: boolean, errors: string[] }}
118
+ */
119
+ validate() {
120
+ const errors = [];
121
+ if (this.pendingWrites.size === 0) {
122
+ errors.push('No pending writes in transaction');
123
+ return { valid: false, errors };
124
+ }
125
+ for (const [filePath, write] of this.pendingWrites) {
126
+ // Check content is defined
127
+ if (write.content === undefined || write.content === null) {
128
+ errors.push(`${write.description}: Content is undefined`);
129
+ continue;
130
+ }
131
+ // Check parent directory exists or can be created
132
+ const dir = path.dirname(filePath);
133
+ if (dir && dir !== '.' && !existsSync(dir)) {
134
+ // Will be created during commit - just note for logging
135
+ console.log(`${LOG_PREFIX.DONE} Will create directory: ${dir}`);
136
+ }
137
+ }
138
+ return { valid: errors.length === 0, errors };
139
+ }
140
+ /**
141
+ * Commit all pending writes atomically
142
+ *
143
+ * Writes all files in a single batch. If any write fails,
144
+ * reports which files were written vs failed.
145
+ *
146
+ * @returns {{ success: boolean, written: string[], failed: { path: string, error: string }[] }}
147
+ * @throws {Error} If transaction already committed or aborted
148
+ */
149
+ commit() {
150
+ if (this.committed) {
151
+ throw createError(ErrorCodes.TRANSACTION_ERROR, `Transaction already committed (${this.wuId})`, { wuId: this.wuId });
152
+ }
153
+ if (this.aborted) {
154
+ throw createError(ErrorCodes.TRANSACTION_ERROR, `Cannot commit aborted transaction (${this.wuId})`, { wuId: this.wuId });
155
+ }
156
+ const written = [];
157
+ const failed = [];
158
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Transaction COMMIT - writing ${this.pendingWrites.size} files atomically`);
159
+ for (const [filePath, write] of this.pendingWrites) {
160
+ try {
161
+ // Ensure parent directory exists
162
+ const dir = path.dirname(filePath);
163
+ if (dir && dir !== '.' && !existsSync(dir)) {
164
+ mkdirSync(dir, { recursive: true });
165
+ }
166
+ // Write file
167
+ writeFileSync(filePath, write.content, { encoding: 'utf-8' });
168
+ written.push(filePath);
169
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} ${write.description}`);
170
+ }
171
+ catch (err) {
172
+ const errMessage = err instanceof Error ? err.message : String(err);
173
+ failed.push({ path: filePath, error: errMessage });
174
+ console.error(`${LOG_PREFIX.DONE} ${EMOJI.FAILURE} ${write.description}: ${errMessage}`);
175
+ }
176
+ }
177
+ this.committed = true;
178
+ this.pendingWrites.clear();
179
+ const success = failed.length === 0;
180
+ if (!success) {
181
+ console.error(`${LOG_PREFIX.DONE} ${EMOJI.WARNING} Transaction completed with ${failed.length} failures`);
182
+ }
183
+ return { success, written, failed };
184
+ }
185
+ /**
186
+ * Abort transaction (discard pending writes)
187
+ *
188
+ * Since no writes have been made, this just clears pending changes.
189
+ * This is the key benefit of the transactional pattern.
190
+ */
191
+ abort() {
192
+ if (this.committed) {
193
+ console.warn(`${LOG_PREFIX.DONE} ${EMOJI.WARNING} Aborting already-committed transaction`);
194
+ return;
195
+ }
196
+ const count = this.pendingWrites.size;
197
+ this.pendingWrites.clear();
198
+ this.aborted = true;
199
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.WARNING} Transaction ABORTED - ${count} pending writes discarded`);
200
+ }
201
+ /**
202
+ * Get transaction state for debugging
203
+ */
204
+ getState() {
205
+ return {
206
+ wuId: this.wuId,
207
+ committed: this.committed,
208
+ aborted: this.aborted,
209
+ pendingCount: this.pendingWrites.size,
210
+ files: Array.from(this.pendingWrites.keys()),
211
+ createdAt: this.createdAt.toISOString(),
212
+ };
213
+ }
214
+ }
215
+ /**
216
+ * Read file content for transaction (pre-compute backup)
217
+ *
218
+ * @param {string} filePath - File to read
219
+ * @returns {string|null} - File content or null if doesn't exist
220
+ */
221
+ export function readFileForTransaction(filePath) {
222
+ if (!existsSync(filePath)) {
223
+ return null;
224
+ }
225
+ return readFileSync(filePath, { encoding: 'utf-8' });
226
+ }
227
+ /**
228
+ * Create a transaction state snapshot for rollback
229
+ *
230
+ * Captures current file contents before any modifications.
231
+ * Used if git operations fail after transaction commit.
232
+ *
233
+ * @param {string[]} filePaths - Paths to snapshot
234
+ * @returns {Map<string, string|null>} - Map of path to content (null = didn't exist)
235
+ */
236
+ export function createTransactionSnapshot(filePaths) {
237
+ const snapshot = new Map();
238
+ for (const filePath of filePaths) {
239
+ snapshot.set(filePath, readFileForTransaction(filePath));
240
+ }
241
+ return snapshot;
242
+ }
243
+ /**
244
+ * Restore files from snapshot (for rollback after commit)
245
+ *
246
+ * @param {Map<string, string|null>} snapshot - Snapshot from createTransactionSnapshot
247
+ * @returns {{ restored: string[], errors: { path: string, error: string }[] }}
248
+ */
249
+ export function restoreFromSnapshot(snapshot) {
250
+ const restored = [];
251
+ const errors = [];
252
+ for (const [filePath, content] of snapshot) {
253
+ try {
254
+ if (content === null) {
255
+ // File didn't exist before - delete if it exists now
256
+ if (existsSync(filePath)) {
257
+ unlinkSync(filePath);
258
+ restored.push(filePath);
259
+ }
260
+ }
261
+ else {
262
+ // Restore original content
263
+ writeFileSync(filePath, content, { encoding: 'utf-8' });
264
+ restored.push(filePath);
265
+ }
266
+ }
267
+ catch (err) {
268
+ const errMessage = err instanceof Error ? err.message : String(err);
269
+ errors.push({ path: filePath, error: errMessage });
270
+ }
271
+ }
272
+ return { restored, errors };
273
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * WU Validation Constants (WU-1243)
3
+ *
4
+ * Centralizes magic numbers for lane inference and incident validation.
5
+ * Extracted from lane-inference.mjs and agent-incidents.mjs for DRY compliance.
6
+ *
7
+ * @module wu-validation-constants
8
+ */
9
+ /**
10
+ * Lane inference scoring weights.
11
+ * Code path matches are weighted higher than keywords because
12
+ * file paths are more reliable signals for lane classification.
13
+ *
14
+ * The 10:3 ratio (~3.3x) reflects that a code path match is approximately
15
+ * 3x more indicative of the correct lane than a keyword match.
16
+ */
17
+ export declare const WEIGHTS: {
18
+ /** Weight for code path pattern matches (more reliable signal) */
19
+ CODE_PATH_MATCH: number;
20
+ /** Weight for keyword matches in description (less specific signal) */
21
+ KEYWORD_MATCH: number;
22
+ };
23
+ /**
24
+ * Confidence score configuration for lane inference.
25
+ *
26
+ * WU-2438: Changed from percentage-based (0-100) to absolute scoring.
27
+ * Raw scores (sum of WEIGHTS) are now returned directly.
28
+ * Higher score = better match, regardless of config size.
29
+ */
30
+ export declare const CONFIDENCE: {
31
+ /** Minimum confidence value (no matches) */
32
+ MIN: number;
33
+ /** Maximum confidence value (legacy, kept for backward compatibility) */
34
+ MAX: number;
35
+ /**
36
+ * Minimum confidence threshold to return a suggestion.
37
+ * Set to 0 to always return best match (even low confidence).
38
+ * Note: With absolute scoring, this threshold is compared against raw scores.
39
+ */
40
+ THRESHOLD: number;
41
+ };
42
+ /**
43
+ * String length validation limits for incident logging.
44
+ * Prevents abuse while allowing meaningful content.
45
+ */
46
+ export declare const VALIDATION_LIMITS: {
47
+ /** Minimum title length (prevents truncated/empty titles) */
48
+ TITLE_MIN: number;
49
+ /** Maximum title length (keeps logs readable) */
50
+ TITLE_MAX: number;
51
+ /** Minimum description length (prevents one-liners) */
52
+ DESCRIPTION_MIN: number;
53
+ /** Maximum description length (prevents unbounded logging) */
54
+ DESCRIPTION_MAX: number;
55
+ };
56
+ /**
57
+ * Valid incident categories for agent issue logging.
58
+ * Duplicated from agent-incidents.mjs z.enum for use in default arrays.
59
+ */
60
+ export declare const INCIDENT_CATEGORIES: readonly ["workflow", "tooling", "confusion", "violation", "error"];
@@ -0,0 +1,66 @@
1
+ /**
2
+ * WU Validation Constants (WU-1243)
3
+ *
4
+ * Centralizes magic numbers for lane inference and incident validation.
5
+ * Extracted from lane-inference.mjs and agent-incidents.mjs for DRY compliance.
6
+ *
7
+ * @module wu-validation-constants
8
+ */
9
+ /**
10
+ * Lane inference scoring weights.
11
+ * Code path matches are weighted higher than keywords because
12
+ * file paths are more reliable signals for lane classification.
13
+ *
14
+ * The 10:3 ratio (~3.3x) reflects that a code path match is approximately
15
+ * 3x more indicative of the correct lane than a keyword match.
16
+ */
17
+ export const WEIGHTS = {
18
+ /** Weight for code path pattern matches (more reliable signal) */
19
+ CODE_PATH_MATCH: 10,
20
+ /** Weight for keyword matches in description (less specific signal) */
21
+ KEYWORD_MATCH: 3,
22
+ };
23
+ /**
24
+ * Confidence score configuration for lane inference.
25
+ *
26
+ * WU-2438: Changed from percentage-based (0-100) to absolute scoring.
27
+ * Raw scores (sum of WEIGHTS) are now returned directly.
28
+ * Higher score = better match, regardless of config size.
29
+ */
30
+ export const CONFIDENCE = {
31
+ /** Minimum confidence value (no matches) */
32
+ MIN: 0,
33
+ /** Maximum confidence value (legacy, kept for backward compatibility) */
34
+ MAX: 100,
35
+ /**
36
+ * Minimum confidence threshold to return a suggestion.
37
+ * Set to 0 to always return best match (even low confidence).
38
+ * Note: With absolute scoring, this threshold is compared against raw scores.
39
+ */
40
+ THRESHOLD: 0,
41
+ };
42
+ /**
43
+ * String length validation limits for incident logging.
44
+ * Prevents abuse while allowing meaningful content.
45
+ */
46
+ export const VALIDATION_LIMITS = {
47
+ /** Minimum title length (prevents truncated/empty titles) */
48
+ TITLE_MIN: 5,
49
+ /** Maximum title length (keeps logs readable) */
50
+ TITLE_MAX: 100,
51
+ /** Minimum description length (prevents one-liners) */
52
+ DESCRIPTION_MIN: 10,
53
+ /** Maximum description length (prevents unbounded logging) */
54
+ DESCRIPTION_MAX: 2000,
55
+ };
56
+ /**
57
+ * Valid incident categories for agent issue logging.
58
+ * Duplicated from agent-incidents.mjs z.enum for use in default arrays.
59
+ */
60
+ export const INCIDENT_CATEGORIES = [
61
+ 'workflow',
62
+ 'tooling',
63
+ 'confusion',
64
+ 'violation',
65
+ 'error',
66
+ ];
@@ -0,0 +1,118 @@
1
+ /**
2
+ * WU Exposure Validation (WU-1999, WU-2022)
3
+ *
4
+ * WU-1999: Validates exposure field and UI pairing for wu:done.
5
+ * Provides warnings (not errors) to guide completion without blocking.
6
+ *
7
+ * WU-2022: Adds BLOCKING validation for feature accessibility.
8
+ * When exposure=ui, ensures the feature is actually accessible via navigation.
9
+ *
10
+ * Part of INIT-031 Phase 4: Prevent backend-without-UI pattern.
11
+ *
12
+ * @see {@link tools/wu-done.mjs} - Consumer
13
+ * @see {@link tools/lib/wu-schema.mjs} - WU schema with exposure field
14
+ * @see {@link tools/lib/wu-constants.mjs} - WU_EXPOSURE values
15
+ */
16
+ /**
17
+ * Warning message templates with remediation guidance.
18
+ * All messages include the WU ID for context.
19
+ */
20
+ export declare const EXPOSURE_WARNING_MESSAGES: {
21
+ /**
22
+ * Warning when exposure field is missing entirely.
23
+ * @param {string} wuId - The WU identifier
24
+ * @returns {string} Warning message with remediation
25
+ */
26
+ MISSING_EXPOSURE: (wuId: any) => string;
27
+ /**
28
+ * Warning when API exposure lacks UI pairing WUs.
29
+ * @param {string} wuId - The WU identifier
30
+ * @returns {string} Warning message with remediation
31
+ */
32
+ MISSING_UI_PAIRING: (wuId: any) => string;
33
+ /**
34
+ * Warning when API exposure lacks UI verification in acceptance criteria.
35
+ * @param {string} wuId - The WU identifier
36
+ * @returns {string} Warning message with remediation
37
+ */
38
+ MISSING_UI_VERIFICATION: (wuId: any) => string;
39
+ /**
40
+ * Recommendation for user_journey when exposure is UI.
41
+ * @param {string} wuId - The WU identifier
42
+ * @returns {string} Warning message with remediation
43
+ */
44
+ MISSING_USER_JOURNEY: (wuId: any) => string;
45
+ };
46
+ /**
47
+ * Validate exposure field and UI pairing for a WU.
48
+ *
49
+ * This is a non-blocking validation that returns warnings, not errors.
50
+ * Use during wu:done to guide completion without preventing it.
51
+ *
52
+ * Checks:
53
+ * 1. exposure field is present (warns if missing)
54
+ * 2. If exposure=api, warns if no ui_pairing_wus specified
55
+ * 3. If exposure=api, checks acceptance criteria for UI verification mention
56
+ * 4. If exposure=ui, recommends user_journey field if not present
57
+ *
58
+ * @param {object} wu - WU YAML object
59
+ * @param {string} wu.id - WU identifier
60
+ * @param {string} [wu.exposure] - Exposure type (ui, api, backend-only, documentation)
61
+ * @param {string[]} [wu.ui_pairing_wus] - Related UI WU IDs for API exposure
62
+ * @param {string} [wu.user_journey] - User journey description for UI exposure
63
+ * @param {string[]|object} [wu.acceptance] - Acceptance criteria
64
+ * @param {ValidateExposureOptions} [options] - Validation options
65
+ * @returns {{valid: boolean, warnings: string[]}} Validation result
66
+ */
67
+ interface ValidateExposureOptions {
68
+ /** Skip all exposure validation */
69
+ skipExposureCheck?: boolean;
70
+ }
71
+ export declare function validateExposure(wu: any, options?: ValidateExposureOptions): {
72
+ valid: boolean;
73
+ warnings: any[];
74
+ };
75
+ /**
76
+ * Error message templates for accessibility validation (WU-2022).
77
+ * These are BLOCKING errors, not warnings.
78
+ */
79
+ export declare const ACCESSIBILITY_ERROR_MESSAGES: {
80
+ /**
81
+ * Error when UI exposure lacks navigation accessibility proof.
82
+ * @param {string} wuId - The WU identifier
83
+ * @returns {string} Error message with remediation guidance
84
+ */
85
+ UI_NOT_ACCESSIBLE: (wuId: any) => string;
86
+ };
87
+ /**
88
+ * Validate feature accessibility for UI-exposed WUs (WU-2022).
89
+ *
90
+ * This is a BLOCKING validation that returns errors (not warnings).
91
+ * When exposure=ui, the feature must be verifiably accessible.
92
+ *
93
+ * Accessibility is verified by ANY of:
94
+ * 1. navigation_path field is specified (explicit route)
95
+ * 2. code_paths includes a page.tsx file (Next.js page)
96
+ * 3. tests.manual includes navigation/accessibility verification
97
+ *
98
+ * Non-UI exposures (api, backend-only, documentation) pass automatically.
99
+ * Missing exposure field passes (legacy WUs, handled by WU-1999 warning).
100
+ *
101
+ * @param {object} wu - WU YAML object
102
+ * @param {string} wu.id - WU identifier
103
+ * @param {string} [wu.exposure] - Exposure type (ui, api, backend-only, documentation)
104
+ * @param {string} [wu.navigation_path] - Route where UI is accessible
105
+ * @param {string[]} [wu.code_paths] - Files modified by this WU
106
+ * @param {object} [wu.tests] - Test specifications
107
+ * @param {ValidateFeatureAccessibilityOptions} [options] - Validation options
108
+ * @returns {{valid: boolean, errors: string[]}} Validation result
109
+ */
110
+ interface ValidateFeatureAccessibilityOptions {
111
+ /** Skip all accessibility validation */
112
+ skipAccessibilityCheck?: boolean;
113
+ }
114
+ export declare function validateFeatureAccessibility(wu: any, options?: ValidateFeatureAccessibilityOptions): {
115
+ valid: boolean;
116
+ errors: any[];
117
+ };
118
+ export {};