@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,233 @@
1
+ /**
2
+ * WU-1747: WU Checkpoint Module
3
+ *
4
+ * Provides checkpoint-based gate resumption for wu:done operations.
5
+ * Allows failed wu:done to resume from checkpoint without re-running gates
6
+ * if nothing has changed since the checkpoint was created.
7
+ *
8
+ * Features:
9
+ * - Pre-gates checkpoint creation with worktree state
10
+ * - SHA-based change detection
11
+ * - Schema versioning for forward compatibility
12
+ * - Automatic stale checkpoint cleanup
13
+ *
14
+ * @module wu-checkpoint
15
+ */
16
+ import { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync } from 'node:fs';
17
+ import path from 'node:path';
18
+ import crypto from 'node:crypto';
19
+ import { LOG_PREFIX, EMOJI } from './wu-constants.js';
20
+ /**
21
+ * Schema version for checkpoint files
22
+ * Increment when checkpoint format changes
23
+ */
24
+ export const CHECKPOINT_SCHEMA_VERSION = 1;
25
+ /**
26
+ * Checkpoint directory within .beacon
27
+ */
28
+ const CHECKPOINT_DIR = 'checkpoints';
29
+ /**
30
+ * Maximum age for a checkpoint before it's considered stale (24 hours)
31
+ */
32
+ const CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1000;
33
+ /**
34
+ * Get the path to a checkpoint file
35
+ *
36
+ * @param {string} wuId - WU ID
37
+ * @param {CheckpointBaseDirOptions} [options]
38
+ * @returns {string} Path to checkpoint file
39
+ */
40
+ function getCheckpointPath(wuId, options = {}) {
41
+ const baseDir = options.baseDir || process.cwd();
42
+ return path.join(baseDir, '.beacon', CHECKPOINT_DIR, `${wuId}.checkpoint.json`);
43
+ }
44
+ /**
45
+ * Ensure checkpoint directory exists
46
+ *
47
+ * @param {CheckpointBaseDirOptions} [options]
48
+ */
49
+ function ensureCheckpointDir(options = {}) {
50
+ const baseDir = options.baseDir || process.cwd();
51
+ const checkpointDir = path.join(baseDir, '.beacon', CHECKPOINT_DIR);
52
+ if (!existsSync(checkpointDir)) {
53
+ mkdirSync(checkpointDir, { recursive: true });
54
+ }
55
+ }
56
+ /**
57
+ * Generate a unique checkpoint ID
58
+ *
59
+ * @returns {string} Unique checkpoint ID
60
+ */
61
+ function generateCheckpointId() {
62
+ return `ckpt-${crypto.randomUUID().slice(0, 8)}`;
63
+ }
64
+ /**
65
+ * Get the current HEAD SHA from a git directory
66
+ * Falls back to placeholder if git operations fail
67
+ *
68
+ * @param {string} dir - Directory to get HEAD SHA from
69
+ * @returns {string} HEAD SHA or placeholder
70
+ */
71
+ function getHeadSha(dir) {
72
+ try {
73
+ // Try to read .git/HEAD directly for speed
74
+ const gitDir = path.join(dir, '.git');
75
+ if (existsSync(gitDir)) {
76
+ const headPath = path.join(gitDir, 'HEAD');
77
+ if (existsSync(headPath)) {
78
+ const headContent = readFileSync(headPath, 'utf8').trim();
79
+ // If it's a ref, read the ref file
80
+ if (headContent.startsWith('ref: ')) {
81
+ const refPath = path.join(gitDir, headContent.slice(5));
82
+ if (existsSync(refPath)) {
83
+ return readFileSync(refPath, 'utf8').trim();
84
+ }
85
+ }
86
+ // It's a direct SHA
87
+ return headContent;
88
+ }
89
+ }
90
+ // For worktrees, .git is a file pointing to the main repo
91
+ const gitFile = path.join(dir, '.git');
92
+ if (existsSync(gitFile)) {
93
+ const gitFileContent = readFileSync(gitFile, 'utf8').trim();
94
+ if (gitFileContent.startsWith('gitdir: ')) {
95
+ const worktreeGitDir = gitFileContent.slice(8);
96
+ const headPath = path.join(worktreeGitDir, 'HEAD');
97
+ if (existsSync(headPath)) {
98
+ const headContent = readFileSync(headPath, 'utf8').trim();
99
+ if (headContent.startsWith('ref: ')) {
100
+ // Need to resolve from main repo's refs
101
+ const mainGitDir = path.resolve(worktreeGitDir, '..', '..');
102
+ const refPath = path.join(mainGitDir, headContent.slice(5));
103
+ if (existsSync(refPath)) {
104
+ return readFileSync(refPath, 'utf8').trim();
105
+ }
106
+ }
107
+ return headContent;
108
+ }
109
+ }
110
+ }
111
+ return 'unknown-sha';
112
+ }
113
+ catch {
114
+ return 'unknown-sha';
115
+ }
116
+ }
117
+ /**
118
+ * Create a checkpoint before running gates
119
+ *
120
+ * @param {Object} params - Checkpoint parameters
121
+ * @param {string} params.wuId - WU ID
122
+ * @param {string} params.worktreePath - Path to worktree
123
+ * @param {string} params.branchName - Lane branch name
124
+ * @param {CreatePreGatesCheckpointOptions} [options]
125
+ * @returns {Promise<Checkpoint>} Created checkpoint
126
+ */
127
+ export async function createPreGatesCheckpoint(params, options = {}) {
128
+ const { wuId, worktreePath, branchName, gatesPassed = false } = params;
129
+ const { baseDir } = options;
130
+ ensureCheckpointDir({ baseDir });
131
+ const checkpoint = {
132
+ schemaVersion: CHECKPOINT_SCHEMA_VERSION,
133
+ checkpointId: generateCheckpointId(),
134
+ wuId,
135
+ worktreePath,
136
+ branchName,
137
+ worktreeHeadSha: getHeadSha(worktreePath),
138
+ createdAt: new Date().toISOString(),
139
+ gatesPassed,
140
+ gatesPassedAt: gatesPassed ? new Date().toISOString() : null,
141
+ };
142
+ const checkpointPath = getCheckpointPath(wuId, { baseDir });
143
+ writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2));
144
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Created pre-gates checkpoint for ${wuId}`);
145
+ return checkpoint;
146
+ }
147
+ /**
148
+ * Mark a checkpoint as having passed gates
149
+ *
150
+ * @param {string} wuId - WU ID
151
+ * @param {CheckpointBaseDirOptions} [options]
152
+ * @returns {boolean} True if checkpoint was updated
153
+ */
154
+ export function markGatesPassed(wuId, options = {}) {
155
+ const checkpoint = getCheckpoint(wuId, options);
156
+ if (!checkpoint) {
157
+ return false;
158
+ }
159
+ checkpoint.gatesPassed = true;
160
+ checkpoint.gatesPassedAt = new Date().toISOString();
161
+ const checkpointPath = getCheckpointPath(wuId, options);
162
+ writeFileSync(checkpointPath, JSON.stringify(checkpoint, null, 2));
163
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Marked gates passed for ${wuId}`);
164
+ return true;
165
+ }
166
+ /**
167
+ * Get a checkpoint for a WU
168
+ *
169
+ * @param {string} wuId - WU ID
170
+ * @param {CheckpointBaseDirOptions} [options]
171
+ * @returns {Checkpoint|null} Checkpoint or null if not found
172
+ */
173
+ export function getCheckpoint(wuId, options = {}) {
174
+ const checkpointPath = getCheckpointPath(wuId, options);
175
+ if (!existsSync(checkpointPath)) {
176
+ return null;
177
+ }
178
+ try {
179
+ const content = readFileSync(checkpointPath, 'utf8');
180
+ return JSON.parse(content);
181
+ }
182
+ catch {
183
+ // Corrupted checkpoint - treat as non-existent
184
+ return null;
185
+ }
186
+ }
187
+ /**
188
+ * Clear a checkpoint for a WU
189
+ *
190
+ * @param {string} wuId - WU ID
191
+ * @param {CheckpointBaseDirOptions} [options]
192
+ */
193
+ export function clearCheckpoint(wuId, options = {}) {
194
+ const checkpointPath = getCheckpointPath(wuId, options);
195
+ if (existsSync(checkpointPath)) {
196
+ unlinkSync(checkpointPath);
197
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Cleared checkpoint for ${wuId}`);
198
+ }
199
+ }
200
+ export function canSkipGates(wuId, options = {}) {
201
+ const { baseDir, currentHeadSha } = options;
202
+ const checkpoint = getCheckpoint(wuId, { baseDir });
203
+ // No checkpoint exists
204
+ if (!checkpoint) {
205
+ return { canSkip: false, reason: 'No checkpoint exists' };
206
+ }
207
+ // Schema version mismatch
208
+ if (checkpoint.schemaVersion !== CHECKPOINT_SCHEMA_VERSION) {
209
+ return {
210
+ canSkip: false,
211
+ reason: `Checkpoint schema version mismatch (got ${checkpoint.schemaVersion}, expected ${CHECKPOINT_SCHEMA_VERSION})`,
212
+ };
213
+ }
214
+ // Gates didn't pass at checkpoint
215
+ if (!checkpoint.gatesPassed) {
216
+ return { canSkip: false, reason: 'Gates did not pass at checkpoint' };
217
+ }
218
+ // Check if checkpoint is stale
219
+ const checkpointAge = Date.now() - new Date(checkpoint.createdAt).getTime();
220
+ if (checkpointAge > CHECKPOINT_MAX_AGE_MS) {
221
+ return { canSkip: false, reason: 'Checkpoint is stale (older than 24 hours)' };
222
+ }
223
+ // SHA has changed since checkpoint
224
+ if (currentHeadSha && currentHeadSha !== checkpoint.worktreeHeadSha) {
225
+ return {
226
+ canSkip: false,
227
+ reason: 'Worktree has changed since checkpoint (SHA mismatch)',
228
+ };
229
+ }
230
+ // All checks passed - gates can be skipped
231
+ console.log(`${LOG_PREFIX.DONE} ${EMOJI.SUCCESS} Gates can be skipped - checkpoint valid (${checkpoint.checkpointId})`);
232
+ return { canSkip: true, checkpoint };
233
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file wu-claim-helpers.mjs
3
+ * Helper functions for wu:claim (WU-1423)
4
+ *
5
+ * Extracted email validation logic for testability and SOLID compliance.
6
+ */
7
+ /**
8
+ * Validates if a string is a valid email address.
9
+ *
10
+ * @param {string} value - The string to validate
11
+ * @returns {boolean} True if valid email, false otherwise
12
+ */
13
+ export declare function isValidEmail(value: any): boolean;
14
+ /**
15
+ * Gets a valid email address for WU assignment.
16
+ *
17
+ * Fallback chain (WU-1423):
18
+ * 1. git config user.email
19
+ * 2. GIT_AUTHOR_EMAIL environment variable
20
+ * 3. Error (no silent fallback to username)
21
+ *
22
+ * @param {object} gitAdapter - Git adapter with getConfigValue method
23
+ * @returns {Promise<string>} Valid email address
24
+ * @throws {Error} If no valid email can be determined
25
+ */
26
+ export declare function getAssignedEmail(gitAdapter: any): Promise<any>;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @file wu-claim-helpers.mjs
3
+ * Helper functions for wu:claim (WU-1423)
4
+ *
5
+ * Extracted email validation logic for testability and SOLID compliance.
6
+ */
7
+ import { z } from 'zod';
8
+ /**
9
+ * Zod schema for validating email addresses.
10
+ * Uses Zod's built-in email validation (library-first, no regex).
11
+ */
12
+ const emailSchema = z.string().email();
13
+ /**
14
+ * Validates if a string is a valid email address.
15
+ *
16
+ * @param {string} value - The string to validate
17
+ * @returns {boolean} True if valid email, false otherwise
18
+ */
19
+ export function isValidEmail(value) {
20
+ if (!value || typeof value !== 'string') {
21
+ return false;
22
+ }
23
+ return emailSchema.safeParse(value).success;
24
+ }
25
+ /**
26
+ * Gets a valid email address for WU assignment.
27
+ *
28
+ * Fallback chain (WU-1423):
29
+ * 1. git config user.email
30
+ * 2. GIT_AUTHOR_EMAIL environment variable
31
+ * 3. Error (no silent fallback to username)
32
+ *
33
+ * @param {object} gitAdapter - Git adapter with getConfigValue method
34
+ * @returns {Promise<string>} Valid email address
35
+ * @throws {Error} If no valid email can be determined
36
+ */
37
+ export async function getAssignedEmail(gitAdapter) {
38
+ // Try git config user.email first (WU-1427: properly await async method)
39
+ try {
40
+ const gitEmail = await gitAdapter.getConfigValue('user.email');
41
+ const trimmed = gitEmail?.trim();
42
+ if (trimmed && isValidEmail(trimmed)) {
43
+ return trimmed;
44
+ }
45
+ }
46
+ catch {
47
+ // Git config not available, continue to fallback
48
+ }
49
+ // Fallback to GIT_AUTHOR_EMAIL (commonly set in CI/scripting)
50
+ const authorEmail = process.env.GIT_AUTHOR_EMAIL?.trim();
51
+ if (authorEmail && isValidEmail(authorEmail)) {
52
+ return authorEmail;
53
+ }
54
+ // WU-1423: NO silent fallback to username (GIT_USER, USER)
55
+ // These are usernames, not email addresses, and would cause wu:done validation failures
56
+ throw new Error('Cannot determine assigned_to email address.\n\n' +
57
+ 'Checked:\n' +
58
+ ' 1. git config user.email - not set or invalid\n' +
59
+ ' 2. GIT_AUTHOR_EMAIL env var - not set or invalid\n\n' +
60
+ 'Fix:\n' +
61
+ ' git config --global user.email "you@example.com"\n' +
62
+ ' OR export GIT_AUTHOR_EMAIL="you@example.com"');
63
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @file wu-claim-resume.mjs
3
+ * Helper functions for wu:claim --resume agent handoff (WU-2411)
4
+ *
5
+ * When an agent crashes or is killed, its worktree remains with uncommitted work.
6
+ * The --resume flag allows a new agent to take over by:
7
+ * 1. Verifying the old PID is dead (safety check)
8
+ * 2. Updating the lock file with the new PID
9
+ * 3. Preserving the existing worktree
10
+ * 4. Logging the handoff to the memory layer
11
+ *
12
+ * NOTE: This is WU-specific workflow tooling. No external library provides
13
+ * agent handoff/PID management for git worktrees. Library-first search
14
+ * confirmed no applicable packages exist for this domain-specific logic.
15
+ */
16
+ /**
17
+ * @typedef {Object} ResumeResult
18
+ * @property {boolean} success - Whether the resume operation succeeded
19
+ * @property {boolean} handoff - Whether this was a handoff (vs normal claim)
20
+ * @property {number|null} previousPid - PID of the previous lock holder
21
+ * @property {string|null} previousSession - Session ID of the previous lock holder
22
+ * @property {string|null} error - Error message if operation failed
23
+ * @property {string|null} uncommittedSummary - Summary of uncommitted changes in worktree
24
+ */
25
+ /**
26
+ * Check if a process is running by sending signal 0.
27
+ * This doesn't actually send a signal, but checks if the process exists.
28
+ *
29
+ * @param {number} pid - Process ID to check
30
+ * @returns {boolean} True if process is running, false if not
31
+ */
32
+ export declare function isProcessRunning(pid: any): boolean;
33
+ /**
34
+ * Resume a WU claim from a crashed/killed agent (handoff).
35
+ *
36
+ * This function:
37
+ * 1. Verifies the worktree exists
38
+ * 2. Reads the existing lock file
39
+ * 3. Verifies the old PID is dead (safety check)
40
+ * 4. Updates the lock file with the new PID
41
+ *
42
+ * @param {Object} options - Resume options
43
+ * @param {string} options.wuId - WU ID (e.g., "WU-2411")
44
+ * @param {string} options.lane - Lane name (e.g., "Operations: Tooling")
45
+ * @param {string} options.worktreePath - Path to the existing worktree
46
+ * @param {string} [options.baseDir] - Base directory for lock files (defaults to project root)
47
+ * @param {string} [options.agentSession] - New agent session ID
48
+ * @returns {Promise<ResumeResult>} Result of the resume operation
49
+ */
50
+ export declare function resumeClaimForHandoff(options: any): Promise<{
51
+ success: boolean;
52
+ handoff: boolean;
53
+ previousPid: number;
54
+ previousSession: string;
55
+ error: string;
56
+ uncommittedSummary: any;
57
+ }>;
58
+ /**
59
+ * Get a summary of uncommitted changes in a worktree.
60
+ *
61
+ * @param {Object} gitAdapter - Git adapter with getStatus method
62
+ * @returns {Promise<string|null>} Summary of uncommitted changes, or null if clean
63
+ */
64
+ export declare function getWorktreeUncommittedChanges(gitAdapter: any): Promise<any>;
65
+ /**
66
+ * Format uncommitted changes for display.
67
+ *
68
+ * @param {string} status - Raw git status output
69
+ * @returns {string} Formatted summary for display
70
+ */
71
+ export declare function formatUncommittedChanges(status: any): string;
72
+ /**
73
+ * Create a checkpoint in the memory layer documenting the handoff.
74
+ *
75
+ * @param {Object} options - Checkpoint options
76
+ * @param {string} options.wuId - WU ID
77
+ * @param {number} options.previousPid - Previous owner's PID
78
+ * @param {number} options.newPid - New owner's PID
79
+ * @param {string|null} options.previousSession - Previous owner's session ID
80
+ * @param {string|null} options.uncommittedSummary - Summary of uncommitted changes
81
+ * @param {Object} [options.memoryLayer] - Memory layer interface (for testing)
82
+ * @returns {Promise<{success: boolean, checkpointId?: string, error?: string}>}
83
+ */
84
+ export declare function createHandoffCheckpoint(options: any): Promise<{
85
+ success: boolean;
86
+ checkpointId: any;
87
+ error?: undefined;
88
+ } | {
89
+ success: boolean;
90
+ error: any;
91
+ checkpointId?: undefined;
92
+ }>;
93
+ /**
94
+ * Check if a worktree exists and is valid for resumption.
95
+ *
96
+ * @param {string} worktreePath - Path to check
97
+ * @param {string} _expectedBranch - Expected branch name (unused, for future validation)
98
+ * @returns {{valid: boolean, error?: string}}
99
+ */
100
+ export declare function validateWorktreeForResume(worktreePath: any, _expectedBranch: any): {
101
+ valid: boolean;
102
+ error: string;
103
+ } | {
104
+ valid: boolean;
105
+ error?: undefined;
106
+ };