@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,1382 @@
1
+ /**
2
+ * Work Unit Constants
3
+ *
4
+ * Centralized constants for wu- scripts to ensure consistency and DRY compliance.
5
+ * Single source of truth for magic strings, section headings, and patterns.
6
+ *
7
+ * Part of WU-1214: Extract hardcoded strings to wu-constants.mjs
8
+ * Part of WU-1240: Consolidated toKebab using change-case library
9
+ *
10
+ * @see {@link tools/wu-done.mjs} - Primary consumer
11
+ * @see {@link tools/wu-claim.mjs} - Branch/worktree creation
12
+ * @see {@link tools/lib/wu-schema.mjs} - PLACEHOLDER_SENTINEL (already centralized)
13
+ */
14
+ import path from 'node:path';
15
+ import { kebabCase } from 'change-case';
16
+ /**
17
+ * Git branch names
18
+ */
19
+ export const BRANCHES = {
20
+ MAIN: 'main',
21
+ MASTER: 'master', // Legacy default branch name (defensive check)
22
+ /** Temporary branch prefix for micro-worktree operations */
23
+ TEMP_PREFIX: 'tmp/',
24
+ };
25
+ /**
26
+ * Git remote names
27
+ *
28
+ * WU-1302: Centralized to eliminate hardcoded 'origin' strings
29
+ */
30
+ export const REMOTES = {
31
+ ORIGIN: 'origin',
32
+ };
33
+ /**
34
+ * Git ref construction helpers
35
+ *
36
+ * Centralized to eliminate hardcoded 'origin/main' strings
37
+ */
38
+ export const GIT_REFS = {
39
+ /** Construct remote ref like 'origin/main' */
40
+ remote: (remoteName, branchName) => `${remoteName}/${branchName}`,
41
+ /** Shortcut for origin/main */
42
+ ORIGIN_MAIN: 'origin/main',
43
+ /** Current HEAD ref */
44
+ HEAD: 'HEAD',
45
+ /** Fetch head ref */
46
+ FETCH_HEAD: 'FETCH_HEAD',
47
+ };
48
+ /**
49
+ * WU status values
50
+ *
51
+ * Centralized status strings to avoid magic strings in wu-* scripts.
52
+ * Includes both canonical statuses and legacy variants found in YAML files.
53
+ */
54
+ export const WU_STATUS = {
55
+ // Unclaimed statuses (not yet entered state machine)
56
+ // WU-1374: Legacy backlog status value
57
+ TODO: 'todo',
58
+ READY: 'ready', // Canonical unclaimed status
59
+ BACKLOG: 'backlog', // Legacy variant of ready
60
+ // Active statuses (in state machine)
61
+ IN_PROGRESS: 'in_progress',
62
+ BLOCKED: 'blocked',
63
+ // Terminal statuses (work finished, no further transitions)
64
+ DONE: 'done', // Canonical terminal status
65
+ COMPLETED: 'completed', // Legacy variant of done
66
+ CANCELLED: 'cancelled',
67
+ ABANDONED: 'abandoned',
68
+ DEFERRED: 'deferred',
69
+ CLOSED: 'closed',
70
+ SUPERSEDED: 'superseded',
71
+ };
72
+ /**
73
+ * WU status groups for state management (WU-1742)
74
+ *
75
+ * Used by state-bootstrap.mjs to categorize YAML statuses.
76
+ */
77
+ export const WU_STATUS_GROUPS = {
78
+ /** Statuses representing unclaimed work (not tracked in state store) */
79
+ UNCLAIMED: [WU_STATUS.READY, WU_STATUS.TODO, WU_STATUS.BACKLOG],
80
+ /** Terminal statuses (all map to 'done' in state store) */
81
+ TERMINAL: [
82
+ WU_STATUS.DONE,
83
+ WU_STATUS.COMPLETED,
84
+ WU_STATUS.CANCELLED,
85
+ WU_STATUS.ABANDONED,
86
+ WU_STATUS.DEFERRED,
87
+ WU_STATUS.CLOSED,
88
+ WU_STATUS.SUPERSEDED,
89
+ ],
90
+ };
91
+ /**
92
+ * WU claimed workspace modes
93
+ *
94
+ * Centralized workspace mode strings for wu:claim operations.
95
+ */
96
+ export const CLAIMED_MODES = {
97
+ /** Standard worktree mode (isolated worktree per WU) */
98
+ WORKTREE: 'worktree',
99
+ /** Branch-only mode (no worktree, direct branch work) */
100
+ BRANCH_ONLY: 'branch-only',
101
+ /** Worktree PR mode (worktree with manual PR workflow) */
102
+ WORKTREE_PR: 'worktree-pr',
103
+ };
104
+ /**
105
+ * Agent incident severity levels
106
+ *
107
+ * Centralized severity strings for agent incident reporting.
108
+ */
109
+ export const INCIDENT_SEVERITY = {
110
+ BLOCKER: 'blocker',
111
+ MAJOR: 'major',
112
+ MINOR: 'minor',
113
+ INFO: 'info',
114
+ };
115
+ // Note: PATHS object removed in WU-1240 - use WU_PATHS from wu-paths.mjs instead
116
+ /**
117
+ * Backlog section headings (with emojis)
118
+ *
119
+ * These match the frontmatter config in backlog.md
120
+ */
121
+ export const BACKLOG_SECTIONS = {
122
+ READY: '## 🚀 Ready (pull from here)',
123
+ IN_PROGRESS: '## 🔧 In progress',
124
+ BLOCKED: '## ⛔ Blocked',
125
+ DONE: '## ✅ Done',
126
+ };
127
+ /**
128
+ * Backlog bullet format types (WU-1444)
129
+ *
130
+ * Used by BacklogManager to format list items in each section.
131
+ * Each format produces a different markdown bullet style.
132
+ */
133
+ export const BACKLOG_BULLET_FORMAT = {
134
+ /** Ready format: '- [ ] [WU-ID — Title](link)' */
135
+ READY: 'ready',
136
+ /** Progress format: '- [WU-ID — Title](link)' */
137
+ PROGRESS: 'progress',
138
+ /** Blocked format: '- [ ] [WU-ID — Title](link) — Reason' */
139
+ BLOCKED: 'blocked',
140
+ /** Done format: '- [x] [WU-ID — Title](link) (YYYY-MM-DD)' */
141
+ DONE: 'done',
142
+ };
143
+ /**
144
+ * Status.md section headings (simpler format)
145
+ */
146
+ export const STATUS_SECTIONS = {
147
+ IN_PROGRESS: '## In Progress',
148
+ BLOCKED: '## Blocked',
149
+ COMPLETED: '## Completed',
150
+ };
151
+ /**
152
+ * Regex patterns for WU operations
153
+ *
154
+ * Note: WU_ID pattern is also in wu-schema.mjs for Zod validation
155
+ */
156
+ export const PATTERNS = {
157
+ /** WU identifier format: WU-123 */
158
+ WU_ID: /^WU-\d+$/,
159
+ /** Extract WU ID from text: captures "WU-123" */
160
+ WU_ID_EXTRACT: /WU-\d+/,
161
+ /** Lane branch format: lane/<lane-kebab>/wu-<id> */
162
+ LANE_BRANCH: /^lane\/[\w-]+\/wu-\d+$/,
163
+ /** Worktree path format: worktrees/<lane-kebab>-wu-<id> */
164
+ WORKTREE_PATH: /^worktrees\/[\w-]+-wu-\d+$/,
165
+ };
166
+ /**
167
+ * Commit message formats
168
+ *
169
+ * These are functions that generate properly formatted commit messages
170
+ */
171
+ export const COMMIT_FORMATS = {
172
+ /**
173
+ * wu:claim commit message
174
+ * @param {string} id - WU ID (e.g., 'wu-123')
175
+ * @param {string} laneKebab - Lane in kebab-case (e.g., 'operations-tooling')
176
+ * @returns {string} Commit message
177
+ */
178
+ CLAIM: (id, laneKebab) => `wu(${id}): claim for ${laneKebab} lane`,
179
+ /**
180
+ * wu:done commit message
181
+ * @param {string} id - WU ID (e.g., 'wu-123')
182
+ * @param {string} title - WU title (will be truncated if needed)
183
+ * @returns {string} Commit message
184
+ */
185
+ DONE: (id, title) => `wu(${id}): done - ${title}`,
186
+ /**
187
+ * wu:create commit message
188
+ * @param {string} id - WU ID (e.g., 'wu-123')
189
+ * @param {string} title - WU title (will be truncated if needed)
190
+ * @returns {string} Commit message
191
+ */
192
+ CREATE: (id, title) => `docs: create ${id.toLowerCase()} for ${title}`,
193
+ /**
194
+ * wu:edit commit message (for ready WUs via micro-worktree)
195
+ * @param {string} id - WU ID (e.g., 'wu-123')
196
+ * @returns {string} Commit message
197
+ */
198
+ EDIT: (id) => `docs: edit ${id.toLowerCase()} spec`,
199
+ /**
200
+ * wu:edit spec update commit message (for in_progress WUs in active worktree)
201
+ * WU-1365: Worktree-aware editing applies edits directly in the worktree
202
+ * @param {string} id - WU ID (e.g., 'wu-123')
203
+ * @returns {string} Commit message
204
+ */
205
+ SPEC_UPDATE: (id) => `wu(${id.toLowerCase()}): spec update`,
206
+ /**
207
+ * wu:block commit message
208
+ * @param {string} id - WU ID (e.g., 'wu-123')
209
+ * @returns {string} Commit message
210
+ */
211
+ BLOCK: (id) => `wu(${id}): block`,
212
+ /**
213
+ * wu:unblock commit message
214
+ * @param {string} id - WU ID (e.g., 'wu-123')
215
+ * @returns {string} Commit message
216
+ */
217
+ UNBLOCK: (id) => `wu(${id}): unblock`,
218
+ /**
219
+ * wu:repair commit message
220
+ * @param {string} id - WU ID (e.g., 'wu-123')
221
+ * @returns {string} Commit message
222
+ */
223
+ REPAIR: (id) => `fix(${id}): repair state inconsistency`,
224
+ /**
225
+ * Rebase artifact cleanup commit message
226
+ * WU-1371: Used when rebasing brings in completion artifacts from main
227
+ * @param {string} id - WU ID (e.g., 'wu-123')
228
+ * @returns {string} Commit message
229
+ */
230
+ REBASE_ARTIFACT_CLEANUP: (id) => `chore(${id.toLowerCase()}): remove rebased completion artifacts`,
231
+ /**
232
+ * Backlog repair commit message
233
+ * WU-1506: Used when backlog invariant repair removes duplicates after rebase
234
+ * @param {string} id - WU ID (e.g., 'wu-123')
235
+ * @returns {string} Commit message
236
+ */
237
+ BACKLOG_REPAIR: (id) => `chore(repair): repair backlog duplicates for ${id.toLowerCase()}`,
238
+ };
239
+ /**
240
+ * Log prefixes for wu- scripts
241
+ *
242
+ * Consistent prefixes for console output
243
+ */
244
+ export const LOG_PREFIX = {
245
+ DONE: '[wu-done]',
246
+ CLAIM: '[wu-claim]',
247
+ CREATE: '[wu:create]',
248
+ EDIT: '[wu:edit]',
249
+ DELETE: '[wu:delete]',
250
+ BLOCK: '[wu-block]',
251
+ UNBLOCK: '[wu-unblock]',
252
+ UNLOCK_LANE: '[wu-unlock-lane]',
253
+ CLEANUP: '[wu-cleanup]',
254
+ PRUNE: '[wu-prune]',
255
+ REPAIR: '[wu:repair]',
256
+ CONSISTENCY: '[wu-consistency]',
257
+ PREFLIGHT: '[wu-preflight]',
258
+ INIT_PLAN: '[init:plan]',
259
+ };
260
+ /**
261
+ * Consistency check types (WU-1276)
262
+ *
263
+ * Layer 2 defense-in-depth: detect and repair WU state inconsistencies
264
+ */
265
+ export const CONSISTENCY_TYPES = {
266
+ /** WU YAML has status 'done' but WU appears in status.md In Progress section */
267
+ YAML_DONE_STATUS_IN_PROGRESS: 'YAML_DONE_STATUS_IN_PROGRESS',
268
+ /** WU appears in both Done AND In Progress sections of backlog.md */
269
+ BACKLOG_DUAL_SECTION: 'BACKLOG_DUAL_SECTION',
270
+ /** WU YAML has status 'done' but no stamp file exists */
271
+ YAML_DONE_NO_STAMP: 'YAML_DONE_NO_STAMP',
272
+ /** WU has status 'done' but still has an associated worktree */
273
+ ORPHAN_WORKTREE_DONE: 'ORPHAN_WORKTREE_DONE',
274
+ /** Stamp file exists but WU YAML status is not 'done' (partial wu:done failure) */
275
+ STAMP_EXISTS_YAML_NOT_DONE: 'STAMP_EXISTS_YAML_NOT_DONE',
276
+ };
277
+ /**
278
+ * File system constants
279
+ *
280
+ * WU-923: Centralized to eliminate hardcoded strings
281
+ */
282
+ export const FILE_SYSTEM = {
283
+ /** Standard file encoding */
284
+ ENCODING: 'utf8',
285
+ /** UTF-8 encoding (alias for compatibility) */
286
+ UTF8: 'utf8',
287
+ };
288
+ /**
289
+ * Process stdio constants
290
+ *
291
+ * Standard values for child_process execSync stdio option.
292
+ */
293
+ export const STDIO = {
294
+ /** Pipe stdout/stderr (capture output) */
295
+ PIPE: 'pipe',
296
+ /** Inherit stdio from parent process */
297
+ INHERIT: 'inherit',
298
+ /** Ignore stdio (silent execution) */
299
+ IGNORE: 'ignore',
300
+ };
301
+ /**
302
+ * Configuration file paths
303
+ *
304
+ * WU-923: Centralized config file names
305
+ */
306
+ export const CONFIG_FILES = {
307
+ /** LumenFlow main config */
308
+ LUMENFLOW_CONFIG: '.lumenflow.config.yaml',
309
+ /** Lane inference taxonomy */
310
+ LANE_INFERENCE: '.lumenflow.lane-inference.yaml',
311
+ };
312
+ /**
313
+ * Micro-worktree operation identifiers
314
+ *
315
+ * WU-923: Centralized operation names for withMicroWorktree()
316
+ */
317
+ export const MICRO_WORKTREE_OPERATIONS = {
318
+ WU_CREATE: 'wu-create',
319
+ WU_EDIT: 'wu-edit',
320
+ WU_DELETE: 'wu-delete', // WU-1809: Safe WU deletion
321
+ WU_DONE: 'wu-done',
322
+ WU_BLOCK: 'wu-block',
323
+ WU_UNBLOCK: 'wu-unblock',
324
+ WU_CLAIM: 'wu-claim',
325
+ ORPHAN_REPAIR: 'orphan-repair', // WU-1437: Pre-claim orphan WU repair
326
+ INITIATIVE_EDIT: 'initiative-edit', // WU-1451: Initiative edit operation
327
+ INITIATIVE_BULK_ASSIGN: 'initiative-bulk-assign', // WU-2553: Bulk WU assignment
328
+ };
329
+ /**
330
+ * Telemetry step identifiers
331
+ *
332
+ * WU-1584: Centralized telemetry step names to eliminate string literals.
333
+ */
334
+ export const TELEMETRY_STEPS = {
335
+ GATES: 'gates',
336
+ COS_GATES: 'cos-gates',
337
+ PARALLEL_DETECTION: 'parallel_detection',
338
+ PARALLEL_AUTO_REBASE: 'parallel_auto_rebase',
339
+ };
340
+ /**
341
+ * WU-1747: Skip gates reason constants
342
+ */
343
+ export const SKIP_GATES_REASONS = {
344
+ CHECKPOINT_VALID: 'checkpoint_valid',
345
+ };
346
+ /**
347
+ * WU-1747: Checkpoint-related log messages
348
+ */
349
+ export const CHECKPOINT_MESSAGES = {
350
+ SKIPPING_GATES_VALID: 'Skipping gates - valid checkpoint found',
351
+ CHECKPOINT_LABEL: 'Checkpoint',
352
+ GATES_PASSED_AT: 'Gates passed at',
353
+ COULD_NOT_CREATE: 'Could not create WU-1747 checkpoint',
354
+ };
355
+ /**
356
+ * Default values
357
+ */
358
+ export const DEFAULTS = {
359
+ /** Default worktrees directory */
360
+ WORKTREES_DIR: 'worktrees',
361
+ /** Maximum commit subject length (commitlint default) */
362
+ MAX_COMMIT_SUBJECT: 100,
363
+ /** Parent directory traversal depth from tools/lib to project root */
364
+ PROJECT_ROOT_DEPTH: 2,
365
+ };
366
+ /**
367
+ * YAML serialization options
368
+ *
369
+ * Centralized from duplicated { lineWidth: 100 } across wu-* scripts (WU-1256).
370
+ * Use with js-yaml dump() function.
371
+ */
372
+ export const YAML_OPTIONS = {
373
+ /** Standard line width for YAML dump (100 chars) */
374
+ LINE_WIDTH: 100,
375
+ /** No line wrapping (-1 disables wrapping in js-yaml) */
376
+ NO_WRAP: -1,
377
+ };
378
+ /**
379
+ * UI display constants
380
+ *
381
+ * WU-1281: Centralized from hardcoded values in wu-done.mjs
382
+ */
383
+ export const UI = {
384
+ /** Width for error/info boxes in console output */
385
+ ERROR_BOX_WIDTH: 70,
386
+ /** Number of lines to show in status file preview */
387
+ STATUS_PREVIEW_LINES: 5,
388
+ };
389
+ /**
390
+ * Box drawing characters for console output
391
+ *
392
+ * Emergency fix (Session 2): Centralized to eliminate sonarjs/no-duplicate-string errors
393
+ * Used for recovery dialogs and error boxes in wu-* scripts
394
+ */
395
+ export const BOX = {
396
+ /** Top border: ╔══...══╗ (66 chars inside + corners = 68 total) */
397
+ TOP: '╔══════════════════════════════════════════════════════════════════╗',
398
+ /** Middle separator: ╠══...══╣ */
399
+ MID: '╠══════════════════════════════════════════════════════════════════╣',
400
+ /** Bottom border: ╚══...══╝ */
401
+ BOT: '╚══════════════════════════════════════════════════════════════════╝',
402
+ /** Side border for content lines */
403
+ SIDE: '║',
404
+ };
405
+ /**
406
+ * Git display constants
407
+ *
408
+ * Emergency fix (Session 2): Centralized from hardcoded magic numbers
409
+ * Used for display truncation of SHAs and session IDs
410
+ */
411
+ export const GIT = {
412
+ /** Standard length for displaying short SHA hashes (e.g., "abc12345") */
413
+ SHA_SHORT_LENGTH: 8,
414
+ /** Max number of commits to inspect in git log lookbacks */
415
+ LOG_MAX_COUNT: 50,
416
+ };
417
+ /**
418
+ * Real git executable path - MUST bypass tools/shims to prevent recursion.
419
+ *
420
+ * CRITICAL: The git shim (tools/shims/git) calls functions that need to run git
421
+ * commands. If those functions use 'git' (which resolves to the shim), we get
422
+ * infinite recursion: shim → helper → git → shim → helper → git → ...
423
+ *
424
+ * With VS Code extensions making dozens of git calls per second, this causes
425
+ * memory exhaustion within seconds → OOM crash → system reboot.
426
+ *
427
+ * P0 incident: 2025-12-10 server crash due to recursive fork bomb.
428
+ *
429
+ * @see tools/shims/git - The git shim that blocks destructive commands
430
+ * @see tools/lib/wu-helpers.mjs - Uses REAL_GIT to avoid recursion
431
+ */
432
+ export const REAL_GIT = '/usr/bin/git';
433
+ /**
434
+ * Git command flags
435
+ *
436
+ * Centralized git flag constants to eliminate hardcoded strings.
437
+ * Used by git-adapter.mjs and other git operation utilities.
438
+ */
439
+ export const GIT_FLAGS = {
440
+ /** Show abbreviated ref names (for branch name resolution) */
441
+ ABBREV_REF: '--abbrev-ref',
442
+ /** Porcelain format (machine-readable output) */
443
+ PORCELAIN: '--porcelain',
444
+ /** Create new branch and switch to it */
445
+ BRANCH: '-b',
446
+ /** Force flag (long form) */
447
+ FORCE: '--force',
448
+ /** Force flag (short form) */
449
+ FORCE_SHORT: '-f',
450
+ /** Fast-forward only merge */
451
+ FF_ONLY: '--ff-only',
452
+ /** Check ancestry without output (merge-base) */
453
+ IS_ANCESTOR: '--is-ancestor',
454
+ /** Set upstream tracking */
455
+ UPSTREAM: '-u',
456
+ /** Delete branch (safe - only if merged) */
457
+ DELETE: '-d',
458
+ /** Delete branch (force - even if not merged) */
459
+ DELETE_FORCE: '-D',
460
+ /** Hard reset flag */
461
+ HARD: '--hard',
462
+ /** Soft reset flag */
463
+ SOFT: '--soft',
464
+ /** fd flags for clean (force delete directories) */
465
+ FD_SHORT: '-fd',
466
+ /** df flags for clean (delete force directories) */
467
+ DF_SHORT: '-df',
468
+ /** No verify flag (skip pre-commit/commit-msg hooks) */
469
+ NO_VERIFY: '--no-verify',
470
+ /** No GPG sign flag (skip commit signing) */
471
+ NO_GPG_SIGN: '--no-gpg-sign',
472
+ };
473
+ /**
474
+ * Git commands
475
+ *
476
+ * Centralized git command strings to eliminate hardcoded strings.
477
+ * Used for direct git command execution via execSync/execa.
478
+ */
479
+ export const GIT_COMMANDS = {
480
+ /** Git binary */
481
+ GIT: 'git',
482
+ /** Git reset command */
483
+ RESET: 'reset',
484
+ /** List tree objects (check file existence on branch) */
485
+ LS_TREE: 'ls-tree',
486
+ /** Git diff command */
487
+ DIFF: 'diff',
488
+ /** Git merge-base command */
489
+ MERGE_BASE: 'merge-base',
490
+ /** Git rev-parse command */
491
+ REV_PARSE: 'rev-parse',
492
+ /** Git diff flags */
493
+ CACHED: '--cached',
494
+ NAME_ONLY: '--name-only',
495
+ DIFF_FILTER_ACM: '--diff-filter=ACM',
496
+ };
497
+ /**
498
+ * Session display constants
499
+ *
500
+ * Emergency fix (Session 2): Centralized from hardcoded magic numbers
501
+ */
502
+ export const SESSION = {
503
+ /** Standard length for displaying session ID prefix (e.g., "sess-123") */
504
+ ID_DISPLAY_LENGTH: 8,
505
+ };
506
+ /**
507
+ * Validation constants
508
+ *
509
+ * WU-1281: Centralized from local constants in validators
510
+ */
511
+ export const VALIDATION = {
512
+ /** Minimum description length for WU spec completeness */
513
+ MIN_DESCRIPTION_LENGTH: 50,
514
+ };
515
+ /**
516
+ * Threshold constants for pre-flight checks
517
+ *
518
+ * WU-1302: Centralized to eliminate magic numbers
519
+ * WU-1370: Added graduated drift thresholds for early warnings
520
+ */
521
+ export const THRESHOLDS = {
522
+ /** Info threshold: commits behind main to suggest rebasing (WU-1370) */
523
+ BRANCH_DRIFT_INFO: 10,
524
+ /** Warning threshold: commits behind main where rebase is recommended (WU-1370) */
525
+ BRANCH_DRIFT_WARNING: 15,
526
+ /** Maximum commits behind main before requiring rebase (WU-755 pre-flight) */
527
+ BRANCH_DRIFT_MAX: 20,
528
+ };
529
+ /**
530
+ * WU type values
531
+ *
532
+ * WU-1281: Centralized from hardcoded strings in validators
533
+ */
534
+ export const WU_TYPES = {
535
+ DOCUMENTATION: 'documentation',
536
+ PROCESS: 'process',
537
+ FEATURE: 'feature',
538
+ TOOLING: 'tooling',
539
+ BUG: 'bug',
540
+ };
541
+ /**
542
+ * WU exposure values (WU-1998)
543
+ *
544
+ * Defines how a WU exposes its functionality to users.
545
+ * Used to ensure backend features have corresponding UI coverage.
546
+ *
547
+ * @see {@link tools/lib/wu-schema.mjs} - Schema validation
548
+ * @see {@link packages/linters/wu-schema-linter.mjs} - Linter validation
549
+ */
550
+ export const WU_EXPOSURE = {
551
+ /** User-facing UI changes (pages, components, widgets) */
552
+ UI: 'ui',
553
+ /** API endpoints that are called by UI or external clients */
554
+ API: 'api',
555
+ /** Backend-only changes (no user visibility) */
556
+ BACKEND_ONLY: 'backend-only',
557
+ /** Documentation changes only */
558
+ DOCUMENTATION: 'documentation',
559
+ };
560
+ /**
561
+ * Array of valid exposure values for schema validation
562
+ * Note: Defined as tuple for Zod enum compatibility
563
+ */
564
+ export const WU_EXPOSURE_VALUES = ['ui', 'api', 'backend-only', 'documentation'];
565
+ /**
566
+ * Test type keys
567
+ *
568
+ * WU-1281: Centralized from hardcoded keys in validators
569
+ */
570
+ export const TEST_TYPES = {
571
+ UNIT: 'unit',
572
+ E2E: 'e2e',
573
+ MANUAL: 'manual',
574
+ INTEGRATION: 'integration',
575
+ };
576
+ /**
577
+ * Safety-critical test glob patterns
578
+ *
579
+ * WU-2242: Centralized list of glob patterns for safety tests that MUST exist.
580
+ * Gates fail if any of these patterns find no matches.
581
+ *
582
+ * These patterns identify tests for:
583
+ * - PHI (Protected Health Information) protection
584
+ * - Escalation triggers
585
+ * - Privacy detection
586
+ * - Constitutional enforcement
587
+ * - Safe prompt wrapping
588
+ * - Crisis/emergency handling
589
+ *
590
+ * @type {string[]}
591
+ */
592
+ export const SAFETY_CRITICAL_TEST_GLOBS = Object.freeze([
593
+ // PHI protection tests
594
+ 'apps/web/src/**/*PHI*.test.{ts,tsx}',
595
+ 'apps/web/src/**/*phi*.test.{ts,tsx}',
596
+ // Escalation trigger tests
597
+ 'apps/web/src/**/*escalation*.test.{ts,tsx}',
598
+ 'apps/web/src/**/*Escalation*.test.{ts,tsx}',
599
+ // Privacy detection tests
600
+ 'apps/web/src/**/*privacy*.test.{ts,tsx}',
601
+ 'apps/web/src/**/*Privacy*.test.{ts,tsx}',
602
+ // Constitutional enforcer tests
603
+ 'apps/web/src/**/*constitutional*.test.{ts,tsx}',
604
+ 'apps/web/src/**/*Constitutional*.test.{ts,tsx}',
605
+ // Safe prompt wrapper tests
606
+ 'apps/web/src/**/*safePrompt*.test.{ts,tsx}',
607
+ 'apps/web/src/**/*SafePrompt*.test.{ts,tsx}',
608
+ // Crisis/emergency handling tests
609
+ 'apps/web/src/**/*crisis*.test.{ts,tsx}',
610
+ 'apps/web/src/**/*Crisis*.test.{ts,tsx}',
611
+ ]);
612
+ /**
613
+ * Emoji constants for consistent console output
614
+ *
615
+ * WU-1281: Centralized from hardcoded emojis across wu-* scripts
616
+ */
617
+ export const EMOJI = {
618
+ SUCCESS: '✅',
619
+ FAILURE: '❌',
620
+ WARNING: '⚠️',
621
+ INFO: 'ℹ️',
622
+ BLOCKED: '⛔',
623
+ ROCKET: '🚀',
624
+ WRENCH: '🔧',
625
+ TARGET: '🎯',
626
+ MEMO: '📝',
627
+ FOLDER: '📍',
628
+ };
629
+ /**
630
+ * Default values for WU YAML fields
631
+ *
632
+ * WU-1337: Centralized defaults for auto-repair in schema validation
633
+ * DRY principle: Single source of truth for optional field defaults
634
+ *
635
+ * Used by wu-schema.mjs Zod transformations to provide sensible defaults
636
+ * when agents omit optional fields, reducing validation errors.
637
+ */
638
+ export const WU_DEFAULTS = {
639
+ /** Default priority level (medium priority) */
640
+ priority: 'P2',
641
+ /** Default status for new WUs */
642
+ status: 'ready',
643
+ /** Default work type */
644
+ type: 'feature',
645
+ /** Default code paths (empty until populated) */
646
+ code_paths: [],
647
+ /** Default test structure (includes all test types) */
648
+ tests: { manual: [], unit: [], integration: [], e2e: [] },
649
+ /** Default artifacts (empty - wu:done adds stamp) */
650
+ artifacts: [],
651
+ /** Default dependencies (no blockers) */
652
+ dependencies: [],
653
+ /** Default risks (none identified) */
654
+ risks: [],
655
+ /** Default notes (empty string, not undefined) */
656
+ notes: '',
657
+ /** Default review requirement (agent-completed WUs) */
658
+ requires_review: false,
659
+ };
660
+ /**
661
+ * Lane-to-code_paths validation patterns (WU-1372)
662
+ *
663
+ * Advisory patterns to warn when a WU's lane doesn't match its code_paths.
664
+ * Each lane parent can define paths to exclude (paths that shouldn't appear
665
+ * for that lane) and paths that are exceptionally allowed.
666
+ *
667
+ * Validation is advisory only - never blocks wu:claim or wu:done.
668
+ *
669
+ * @see {@link tools/lib/lane-validator.mjs} - Validation logic
670
+ */
671
+ export const LANE_PATH_PATTERNS = {
672
+ /**
673
+ * Operations lane should not touch prompt-related paths.
674
+ * These paths belong to the Intelligence lane.
675
+ */
676
+ Operations: {
677
+ exclude: ['ai/prompts/**', 'packages/@patientpath/prompts/**', 'apps/web/src/lib/prompts/**'],
678
+ allowExceptions: [],
679
+ },
680
+ /**
681
+ * Intelligence lane should not touch tooling paths.
682
+ * Exception: tools/lib/prompt-* files are Intelligence-owned.
683
+ */
684
+ Intelligence: {
685
+ exclude: ['tools/**'],
686
+ allowExceptions: ['tools/lib/prompt-*', 'tools/prompts-eval/**'],
687
+ },
688
+ };
689
+ /**
690
+ * Process detection constants for background process warning (WU-1381)
691
+ *
692
+ * Used by process-detector.mjs to identify processes that may interfere
693
+ * with wu:done gates execution.
694
+ */
695
+ export const PROCESS_DETECTION = {
696
+ /**
697
+ * Process names that commonly interfere with gates execution.
698
+ * These processes may:
699
+ * - Write to stdout/stderr (causing mixed output)
700
+ * - Hold file locks that may cause test failures
701
+ * - Consume resources that affect gate performance
702
+ */
703
+ INTERFERING_NAMES: ['node', 'pnpm', 'npm', 'vitest', 'tsx', 'eslint', 'prettier', 'tsc', 'turbo'],
704
+ /** Maximum characters to display for command in warnings */
705
+ CMD_DISPLAY_LIMIT: 60,
706
+ };
707
+ /**
708
+ * CLI argument flags
709
+ *
710
+ * Centralized command-line argument strings to eliminate hardcoded flags.
711
+ * Used across wu-* scripts, gates, and validation tools.
712
+ */
713
+ export const CLI_FLAGS = {
714
+ // Common flags
715
+ DRY_RUN: '--dry-run',
716
+ EXECUTE: '--execute',
717
+ HELP: '--help',
718
+ HELP_SHORT: '-h',
719
+ VERBOSE: '--verbose',
720
+ FIX: '--fix',
721
+ JSON: '--json',
722
+ FORCE: '--force',
723
+ // Gate-specific flags
724
+ DOCS_ONLY: '--docs-only',
725
+ FULL_LINT: '--full-lint',
726
+ FULL_TESTS: '--full-tests', // WU-1920: Force full test suite
727
+ FULL_COVERAGE: '--full-coverage', // WU-2244: Force full coverage (deterministic)
728
+ COVERAGE_MODE: '--coverage-mode=',
729
+ // WU-specific flags
730
+ WU: '--wu',
731
+ ID: '--id',
732
+ ALL: '--all',
733
+ CHECK: '--check',
734
+ TIER: '--tier',
735
+ AGENT_TYPE: '--agent-type',
736
+ DESCRIPTION: '--description',
737
+ ACCEPTANCE: '--acceptance',
738
+ VALIDATE: '--validate',
739
+ REASON: '--reason',
740
+ WEEK: '--week',
741
+ SINCE: '--since',
742
+ };
743
+ /**
744
+ * pnpm/npm command flags
745
+ *
746
+ * Centralized package manager flag strings.
747
+ */
748
+ export const PKG_FLAGS = {
749
+ FILTER: '--filter',
750
+ FROZEN_LOCKFILE: '--frozen-lockfile',
751
+ };
752
+ /**
753
+ * ESLint command flags
754
+ *
755
+ * Centralized ESLint CLI flag strings.
756
+ */
757
+ export const ESLINT_FLAGS = {
758
+ MAX_WARNINGS: '--max-warnings',
759
+ NO_WARN_IGNORED: '--no-warn-ignored',
760
+ CACHE: '--cache',
761
+ CACHE_STRATEGY: '--cache-strategy',
762
+ CACHE_LOCATION: '--cache-location',
763
+ PASS_ON_UNPRUNED: '--pass-on-unpruned-suppressions',
764
+ };
765
+ /**
766
+ * pnpm script names
767
+ *
768
+ * Centralized script names for package.json commands.
769
+ */
770
+ export const SCRIPTS = {
771
+ LINT: 'lint',
772
+ TEST: 'test',
773
+ TEST_UNIT: 'test:unit',
774
+ BUILD: 'build',
775
+ FORMAT: 'format',
776
+ FORMAT_CHECK: 'format:check',
777
+ TYPECHECK: 'typecheck',
778
+ DEV: 'dev',
779
+ SPEC_LINTER: 'spec:linter',
780
+ PROMPTS_LINT: 'prompts:lint',
781
+ RUN: 'run',
782
+ GATES: 'gates',
783
+ COS_GATES: 'cos:gates',
784
+ PRETTIER: 'prettier',
785
+ };
786
+ /**
787
+ * Gate names for quality gates
788
+ *
789
+ * Centralized gate identifiers for gates.mjs and telemetry.
790
+ */
791
+ export const GATE_NAMES = {
792
+ /** WU-2252: Invariants check (runs first, non-bypassable) */
793
+ INVARIANTS: 'invariants',
794
+ FORMAT_CHECK: 'format:check',
795
+ SPEC_LINTER: 'spec:linter',
796
+ PROMPTS_LINT: 'prompts:lint',
797
+ BACKLOG_SYNC: 'backlog-sync',
798
+ SUPABASE_DOCS_LINTER: 'supabase-docs:linter',
799
+ LINT: 'lint',
800
+ TYPECHECK: 'typecheck',
801
+ TEST: 'test',
802
+ COVERAGE: 'coverage',
803
+ /** WU-2062: Safety-critical tests (always run) */
804
+ SAFETY_CRITICAL_TEST: 'safety-critical-test',
805
+ /** WU-2062: Integration tests (for high-risk changes) */
806
+ INTEGRATION_TEST: 'integration-test',
807
+ /** WU-2315: System map validation (warn-only until orphan docs are indexed) */
808
+ SYSTEM_MAP_VALIDATE: 'system-map:validate',
809
+ };
810
+ /**
811
+ * Gate command sentinels (special values for non-shell commands)
812
+ *
813
+ * These are not shell commands but trigger special handling in gates.mjs.
814
+ */
815
+ export const GATE_COMMANDS = {
816
+ /** WU-2252: Triggers invariants check */
817
+ INVARIANTS: 'invariants',
818
+ /** Triggers incremental lint (only changed files) */
819
+ INCREMENTAL: 'incremental',
820
+ /** Triggers incremental tests (only tests related to changed files) - WU-1920 */
821
+ INCREMENTAL_TEST: 'incremental-test',
822
+ /** Triggers coverage gate check */
823
+ COVERAGE_GATE: 'coverage-gate',
824
+ /** WU-2062: Triggers safety-critical tests (always run) */
825
+ SAFETY_CRITICAL_TEST: 'safety-critical-test',
826
+ /** WU-2062: Triggers tiered test execution based on risk */
827
+ TIERED_TEST: 'tiered-test',
828
+ };
829
+ /**
830
+ * Tool paths for scripts
831
+ *
832
+ * Centralized paths to tool scripts.
833
+ */
834
+ export const TOOL_PATHS = {
835
+ VALIDATE_BACKLOG_SYNC: 'node tools/validate-backlog-sync.js',
836
+ SUPABASE_DOCS_LINTER: 'node packages/linters/supabase-docs-linter.js',
837
+ /** WU-2315: System map validator script */
838
+ SYSTEM_MAP_VALIDATE: 'node tools/system-map-validate.js',
839
+ };
840
+ /**
841
+ * CLI mode flags
842
+ *
843
+ * Command-line mode arguments.
844
+ */
845
+ export const CLI_MODES = {
846
+ LOCAL: '--mode=local',
847
+ };
848
+ /**
849
+ * Prettier command flags
850
+ *
851
+ * Centralized prettier CLI flag strings.
852
+ */
853
+ export const PRETTIER_FLAGS = {
854
+ WRITE: '--write',
855
+ };
856
+ /**
857
+ * Package manager commands
858
+ *
859
+ * Centralized pnpm command strings.
860
+ */
861
+ export const PKG_MANAGER = 'pnpm';
862
+ /**
863
+ * Package manager subcommands
864
+ *
865
+ * Centralized pnpm subcommand strings.
866
+ */
867
+ export const PKG_COMMANDS = {
868
+ INSTALL: 'install',
869
+ };
870
+ /**
871
+ * Package names (monorepo workspaces)
872
+ *
873
+ * Centralized package names for --filter usage.
874
+ */
875
+ export const PACKAGES = {
876
+ WEB: 'web',
877
+ APPLICATION: '@patientpath/application',
878
+ DOMAIN: '@patientpath/domain',
879
+ INFRASTRUCTURE: '@patientpath/infrastructure',
880
+ };
881
+ /**
882
+ * Directory paths within the monorepo
883
+ *
884
+ * Centralized directory path strings.
885
+ */
886
+ export const DIRECTORIES = {
887
+ APPS_WEB: 'apps/web/',
888
+ WORKTREES: 'worktrees/',
889
+ AI: 'ai/',
890
+ CLAUDE: '.claude/',
891
+ DOCS: 'docs/',
892
+ PACKAGES: 'packages/',
893
+ TOOLS: 'tools/',
894
+ MEMORY_BANK: 'memory-bank/',
895
+ WU_DIR: 'docs/04-operations/tasks/wu',
896
+ INITIATIVES_DIR: 'docs/04-operations/tasks/initiatives',
897
+ // WU-1814: Paths for active WU detection
898
+ BACKLOG_PATH: 'docs/04-operations/tasks/backlog.md',
899
+ STATUS_PATH: 'docs/04-operations/tasks/status.md',
900
+ };
901
+ /**
902
+ * ESLint cache strategy values
903
+ */
904
+ export const CACHE_STRATEGIES = {
905
+ CONTENT: 'content',
906
+ METADATA: 'metadata',
907
+ };
908
+ /**
909
+ * Process stdio modes
910
+ *
911
+ * Centralized stdio configuration values for child_process operations.
912
+ */
913
+ export const STDIO_MODES = {
914
+ /** Inherit stdio from parent process (shows output in console) */
915
+ INHERIT: 'inherit',
916
+ /** Pipe stdio to parent process (capture output) */
917
+ PIPE: 'pipe',
918
+ /** Ignore stdio (discard output) */
919
+ IGNORE: 'ignore',
920
+ };
921
+ /**
922
+ * Process exit codes
923
+ *
924
+ * Standard exit code values for CLI scripts.
925
+ */
926
+ export const EXIT_CODES = {
927
+ /** Success exit code */
928
+ SUCCESS: 0,
929
+ /** Generic error exit code */
930
+ ERROR: 1,
931
+ /** Fatal or distinct failure exit code */
932
+ FAILURE: 2,
933
+ };
934
+ /**
935
+ * ESLint command names
936
+ *
937
+ * Centralized ESLint command strings.
938
+ */
939
+ export const ESLINT_COMMANDS = {
940
+ /** ESLint CLI command */
941
+ ESLINT: 'eslint',
942
+ };
943
+ /**
944
+ * ESLint default values
945
+ *
946
+ * Default configuration values for ESLint operations.
947
+ */
948
+ export const ESLINT_DEFAULTS = {
949
+ /**
950
+ * Maximum allowed warnings
951
+ *
952
+ * WU-1866: Temporarily increased from 0 to 100 to unblock gates.
953
+ * There are ~82 pre-existing warnings that need proper fixes.
954
+ * TODO: Create follow-up WU to fix warnings and restore zero-warnings policy.
955
+ */
956
+ MAX_WARNINGS: '100',
957
+ };
958
+ /**
959
+ * Git command combinations
960
+ *
961
+ * Full git command strings for common operations.
962
+ */
963
+ export const GIT_COMMAND_STRINGS = {
964
+ /** Get diff of cached (staged) files */
965
+ DIFF_CACHED: 'git diff --cached',
966
+ /** Get names of cached files */
967
+ DIFF_CACHED_NAMES: 'git diff --cached --name-only',
968
+ /** Get names of cached files (added, copied, modified) */
969
+ DIFF_CACHED_ACM: 'git diff --cached --name-only --diff-filter=ACM',
970
+ /** Get cached diff with zero context (used for hook validation) */
971
+ DIFF_CACHED_UNIFIED_ZERO: 'git diff --cached -U0',
972
+ /** Get current branch name */
973
+ REV_PARSE_ABBREV_REF_HEAD: 'git rev-parse --abbrev-ref HEAD',
974
+ };
975
+ /**
976
+ * Path patterns for WU-related files
977
+ */
978
+ export const PATH_PATTERNS = {
979
+ /** Matches WU YAML paths in both legacy and current locations */
980
+ WU_YAML: /(?:memory-bank|docs\/04-operations)\/tasks\/wu\/(WU-\d+)\.ya?ml$/i,
981
+ /** Matches stamp file paths */
982
+ STAMP: /\.beacon\/stamps\/(WU-\d+)\.done$/i,
983
+ };
984
+ /**
985
+ * Common shell commands
986
+ *
987
+ * Centralized command names for child_process operations.
988
+ */
989
+ export const SHELL_COMMANDS = {
990
+ /** Which command (check if executable exists) */
991
+ WHICH: 'which',
992
+ /** Cat command (concatenate files) */
993
+ CAT: 'cat',
994
+ /** Node.js executable */
995
+ NODE: 'node',
996
+ };
997
+ /**
998
+ * External tool commands
999
+ *
1000
+ * Centralized tool command names.
1001
+ */
1002
+ export const TOOLS = {
1003
+ /** Gitleaks secret scanner */
1004
+ GITLEAKS: 'gitleaks',
1005
+ /** ESLint linter */
1006
+ ESLINT: 'eslint',
1007
+ /** Prettier formatter */
1008
+ PRETTIER: 'prettier',
1009
+ /** TypeScript compiler */
1010
+ TSC: 'tsc',
1011
+ };
1012
+ /**
1013
+ * Gitleaks command arguments
1014
+ *
1015
+ * Centralized gitleaks CLI arguments.
1016
+ */
1017
+ export const GITLEAKS_ARGS = {
1018
+ /** Protect mode (scan staged files) */
1019
+ PROTECT: 'protect',
1020
+ /** Staged flag */
1021
+ STAGED: '--staged',
1022
+ /** Verbose output */
1023
+ VERBOSE: '--verbose',
1024
+ };
1025
+ /**
1026
+ * Prettier command arguments
1027
+ *
1028
+ * Centralized prettier CLI arguments.
1029
+ */
1030
+ export const PRETTIER_ARGS = {
1031
+ /** Check formatting without writing */
1032
+ CHECK: '--check',
1033
+ };
1034
+ /**
1035
+ * Audit command arguments
1036
+ *
1037
+ * Centralized pnpm audit CLI arguments.
1038
+ */
1039
+ export const AUDIT_ARGS = {
1040
+ /** Audit subcommand */
1041
+ AUDIT: 'audit',
1042
+ /** Audit level flag */
1043
+ AUDIT_LEVEL_MODERATE: '--audit-level=moderate',
1044
+ /** Ignore registry errors */
1045
+ IGNORE_REGISTRY_ERRORS: '--ignore-registry-errors',
1046
+ /** Auto-fix flag */
1047
+ FIX: '--fix',
1048
+ };
1049
+ /**
1050
+ * Script file paths
1051
+ *
1052
+ * Centralized paths to validation scripts.
1053
+ */
1054
+ export const SCRIPT_PATHS = {
1055
+ /** WU YAML validation */
1056
+ VALIDATE: 'tools/validate.js',
1057
+ /** Prompt registry validation */
1058
+ VALIDATE_PROMPT_REGISTRY: 'tools/validate-prompt-registry.js',
1059
+ };
1060
+ /**
1061
+ * Known package names for vulnerability tracking
1062
+ *
1063
+ * Package identifiers used in dependency auditing.
1064
+ */
1065
+ export const KNOWN_PACKAGES = {
1066
+ /** node-forge crypto library */
1067
+ NODE_FORGE: 'node-forge',
1068
+ /** Next.js framework */
1069
+ NEXT: 'next',
1070
+ /** jsPDF PDF generation library */
1071
+ JSPDF: 'jspdf',
1072
+ };
1073
+ /**
1074
+ * Error codes and messages
1075
+ *
1076
+ * Centralized error identifiers for consistency.
1077
+ */
1078
+ export const ERROR_CODES = {
1079
+ /** Socket timeout error */
1080
+ ERR_SOCKET_TIMEOUT: 'ERR_SOCKET_TIMEOUT',
1081
+ /** Timeout error code */
1082
+ ETIMEDOUT: 'ETIMEDOUT',
1083
+ };
1084
+ /**
1085
+ * Beacon directory paths
1086
+ *
1087
+ * Centralized paths for .beacon directory structure to eliminate hardcoded strings.
1088
+ * Used by telemetry, agent-session, agent-incidents, and commands-logger modules.
1089
+ */
1090
+ export const BEACON_PATHS = {
1091
+ /** WU state store directory */
1092
+ STATE_DIR: '.beacon/state',
1093
+ /** Stamp directory (WU completion markers) */
1094
+ STAMPS_DIR: '.beacon/stamps',
1095
+ /** Merge lock file (runtime coordination, WU-1747) */
1096
+ MERGE_LOCK: '.beacon/merge.lock',
1097
+ /** Base telemetry directory */
1098
+ TELEMETRY: '.beacon/telemetry',
1099
+ /** Flow log file (WU flow events) */
1100
+ FLOW_LOG: '.beacon/flow.log',
1101
+ /** Agent sessions directory */
1102
+ SESSIONS: '.beacon/sessions',
1103
+ /** Agent incidents directory */
1104
+ INCIDENTS: '.beacon/incidents',
1105
+ /** Git commands log file */
1106
+ COMMANDS_LOG: '.beacon/commands.log',
1107
+ };
1108
+ /**
1109
+ * File extensions
1110
+ *
1111
+ * Centralized file extension strings to avoid magic strings.
1112
+ */
1113
+ export const FILE_EXTENSIONS = {
1114
+ /** Newline-delimited JSON format */
1115
+ NDJSON: '.ndjson',
1116
+ /** Markdown format */
1117
+ MARKDOWN: '.md',
1118
+ /** YAML format */
1119
+ YAML: '.yaml',
1120
+ /** Log format */
1121
+ LOG: '.log',
1122
+ /** Stamp files (completion markers) */
1123
+ STAMP: '.done',
1124
+ };
1125
+ /**
1126
+ * String formatting constants
1127
+ *
1128
+ * Centralized string literals for consistent formatting across scripts.
1129
+ * Eliminates hardcoded '\n', ' ', etc. throughout the codebase.
1130
+ */
1131
+ export const STRING_LITERALS = {
1132
+ /** Newline character */
1133
+ NEWLINE: '\n',
1134
+ /** Double newline (paragraph separator) */
1135
+ DOUBLE_NEWLINE: '\n\n',
1136
+ /** Space character */
1137
+ SPACE: ' ',
1138
+ /** Empty string */
1139
+ EMPTY: '',
1140
+ /** Tab character */
1141
+ TAB: '\t',
1142
+ /** Comma separator */
1143
+ COMMA: ',',
1144
+ /** Colon separator */
1145
+ COLON: ':',
1146
+ /** Dash/hyphen */
1147
+ DASH: '-',
1148
+ /** Forward slash */
1149
+ SLASH: '/',
1150
+ };
1151
+ /**
1152
+ * Convert lane name to kebab-case using change-case library
1153
+ *
1154
+ * Provides null-safe wrapper around paramCase for lane naming.
1155
+ * Handles sub-lanes with colon separator and special characters.
1156
+ *
1157
+ * @param {string|null|undefined} lane - Lane name (e.g., 'Operations: Tooling')
1158
+ * @returns {string} Kebab-case lane (e.g., 'operations-tooling')
1159
+ *
1160
+ * @example
1161
+ * toKebab('Operations: Tooling') // 'operations-tooling'
1162
+ * toKebab('Core Systems') // 'core-systems'
1163
+ * toKebab('Intelligence') // 'intelligence'
1164
+ * toKebab(null) // ''
1165
+ * toKebab(undefined) // ''
1166
+ */
1167
+ export function toKebab(lane) {
1168
+ // Null safety: kebabCase throws on null/undefined
1169
+ if (lane == null)
1170
+ return '';
1171
+ const normalized = String(lane).trim();
1172
+ if (normalized === '')
1173
+ return '';
1174
+ return kebabCase(normalized);
1175
+ }
1176
+ /**
1177
+ * Generate worktree path from lane and WU ID
1178
+ *
1179
+ * @param {string} lane - Lane name
1180
+ * @param {string} id - WU ID
1181
+ * @returns {string} Worktree path (e.g., 'worktrees/operations-tooling-wu-123')
1182
+ */
1183
+ export function getWorktreePath(lane, id) {
1184
+ const laneKebab = toKebab(lane);
1185
+ const idLower = id.toLowerCase();
1186
+ return `${DEFAULTS.WORKTREES_DIR}/${laneKebab}-${idLower}`;
1187
+ }
1188
+ /**
1189
+ * Generate lane branch name from lane and WU ID
1190
+ *
1191
+ * @param {string} lane - Lane name
1192
+ * @param {string} id - WU ID
1193
+ * @returns {string} Branch name (e.g., 'lane/operations-tooling/wu-123')
1194
+ */
1195
+ export function getLaneBranch(lane, id) {
1196
+ const laneKebab = toKebab(lane);
1197
+ const idLower = id.toLowerCase();
1198
+ return `lane/${laneKebab}/${idLower}`;
1199
+ }
1200
+ // Note: getWuYamlPath and getStampPath removed in WU-1240
1201
+ // Use WU_PATHS.WU(id) and WU_PATHS.STAMP(id) from wu-paths.mjs instead
1202
+ /**
1203
+ * File tool constants (WU-1403)
1204
+ *
1205
+ * Centralized strings for file:read, file:write, file:edit tools.
1206
+ * Prevents duplicate string literals and hardcoded magic values.
1207
+ */
1208
+ export const FILE_TOOLS = {
1209
+ /** Tool name prefixes */
1210
+ NAMES: {
1211
+ READ: 'file:read',
1212
+ WRITE: 'file:write',
1213
+ EDIT: 'file:edit',
1214
+ DELETE: 'file:delete',
1215
+ },
1216
+ /** Tool domain */
1217
+ DOMAIN: 'file',
1218
+ /** Permission levels */
1219
+ PERMISSIONS: {
1220
+ READ: 'read',
1221
+ WRITE: 'write',
1222
+ },
1223
+ /** Worktree instruction templates (WU-1403: provides reusable instruction strings) */
1224
+ WORKTREE_INSTRUCTIONS: {
1225
+ CLAIM_COMMAND: 'pnpm wu:claim --id <wu-id> --lane "<lane>"',
1226
+ CD_COMMAND: 'cd worktrees/<lane>-<wu-id>/',
1227
+ DOC_REFERENCE: 'CLAUDE.md §2 (Worktree Discipline)',
1228
+ },
1229
+ };
1230
+ /**
1231
+ * PHI (Protected Health Information) error codes (WU-1404)
1232
+ *
1233
+ * Error codes for PHI detection in file tools.
1234
+ * Used by file:write and file:edit to block PHI leakage.
1235
+ */
1236
+ export const PHI_ERRORS = {
1237
+ /** PHI detected in content - write blocked */
1238
+ PHI_DETECTED: 'PHI_DETECTED',
1239
+ /** PHI override requested - audit logged */
1240
+ PHI_OVERRIDE_ALLOWED: 'PHI_OVERRIDE_ALLOWED',
1241
+ };
1242
+ /**
1243
+ * Readiness summary UI constants (WU-1620)
1244
+ *
1245
+ * Constants for the readiness summary box displayed after wu:create and wu:edit.
1246
+ * Provides visual feedback on whether WU is ready for wu:claim.
1247
+ *
1248
+ * @see tools/wu-create.mjs - displayReadinessSummary()
1249
+ * @see tools/wu-edit.mjs - displayReadinessSummary()
1250
+ */
1251
+ export const READINESS_UI = {
1252
+ /** Box width (inner content area) */
1253
+ BOX_WIDTH: 50,
1254
+ /** Box drawing characters */
1255
+ BOX: {
1256
+ TOP_LEFT: '┌',
1257
+ TOP_RIGHT: '┐',
1258
+ BOTTOM_LEFT: '└',
1259
+ BOTTOM_RIGHT: '┘',
1260
+ HORIZONTAL: '─',
1261
+ VERTICAL: '│',
1262
+ },
1263
+ /** Status messages */
1264
+ MESSAGES: {
1265
+ READY_YES: '✅ Ready to claim: YES',
1266
+ READY_NO: '⚠️ Ready to claim: NO',
1267
+ MISSING_HEADER: 'Missing:',
1268
+ BULLET: '•',
1269
+ },
1270
+ /** Error truncation length */
1271
+ ERROR_MAX_LENGTH: 46,
1272
+ ERROR_TRUNCATE_LENGTH: 43,
1273
+ TRUNCATION_SUFFIX: '...',
1274
+ /** Padding calculations (relative to BOX_WIDTH) */
1275
+ PADDING: {
1276
+ READY_YES: 27, // 50 - len("✅ Ready to claim: YES") - 1
1277
+ READY_NO: 28, // 50 - len("⚠️ Ready to claim: NO") - 1
1278
+ MISSING_HEADER: 41, // 50 - len("Missing:") - 1
1279
+ ERROR_BULLET: 45, // 50 - len(" • ") - 1
1280
+ },
1281
+ };
1282
+ /**
1283
+ * Get project root directory from a module URL
1284
+ *
1285
+ * WU-923: Centralized path resolution to eliminate '../..' magic strings
1286
+ *
1287
+ * @param {string} moduleUrl - import.meta.url of the calling module
1288
+ * @returns {string} Absolute path to project root
1289
+ *
1290
+ * @example
1291
+ * import { getProjectRoot } from './lib/wu-constants.js';
1292
+ * const projectRoot = getProjectRoot(import.meta.url);
1293
+ */
1294
+ export function getProjectRoot(moduleUrl) {
1295
+ const { dirname } = path;
1296
+ const currentDir = dirname(new URL(moduleUrl).pathname);
1297
+ // Traverse up from tools/lib to project root
1298
+ let root = currentDir;
1299
+ for (let i = 0; i < DEFAULTS.PROJECT_ROOT_DEPTH; i++) {
1300
+ root = dirname(root);
1301
+ }
1302
+ return root;
1303
+ }
1304
+ /**
1305
+ * Discover safety-critical test files
1306
+ *
1307
+ * WU-2242: Scans for test files matching safety-critical patterns.
1308
+ * Uses glob to find all matching files.
1309
+ *
1310
+ * @param {DiscoverSafetyTestsOptions} options - Discovery options
1311
+ * @returns {Promise<string[]>} List of discovered test file paths
1312
+ */
1313
+ export async function discoverSafetyTests(options = {}) {
1314
+ const { projectRoot = process.cwd() } = options;
1315
+ const { glob } = await import('glob');
1316
+ const foundFiles = [];
1317
+ for (const pattern of SAFETY_CRITICAL_TEST_GLOBS) {
1318
+ try {
1319
+ const matches = await glob(pattern, {
1320
+ cwd: projectRoot,
1321
+ absolute: false,
1322
+ });
1323
+ foundFiles.push(...matches);
1324
+ }
1325
+ catch {
1326
+ // Pattern may not match anything, that's fine
1327
+ }
1328
+ }
1329
+ return [...new Set(foundFiles)]; // Deduplicate
1330
+ }
1331
+ /**
1332
+ * Validate that required safety-critical tests exist
1333
+ *
1334
+ * WU-2242: Checks that each pattern category has at least one matching test file.
1335
+ * Returns a validation result with missing patterns and found files.
1336
+ *
1337
+ * @param {DiscoverSafetyTestsOptions} options - Validation options
1338
+ * @returns {Promise<{valid: boolean, missingTests: string[], foundTests: string[], error?: string}>}
1339
+ */
1340
+ export async function validateSafetyTestsExist(options = {}) {
1341
+ const { projectRoot = process.cwd() } = options;
1342
+ const { glob } = await import('glob');
1343
+ const missingTests = [];
1344
+ const foundTests = [];
1345
+ // Group patterns by category (every 2 patterns form a category)
1346
+ const categories = [
1347
+ { name: 'PHI protection', patterns: SAFETY_CRITICAL_TEST_GLOBS.slice(0, 2) },
1348
+ { name: 'Escalation', patterns: SAFETY_CRITICAL_TEST_GLOBS.slice(2, 4) },
1349
+ { name: 'Privacy detection', patterns: SAFETY_CRITICAL_TEST_GLOBS.slice(4, 6) },
1350
+ { name: 'Constitutional', patterns: SAFETY_CRITICAL_TEST_GLOBS.slice(6, 8) },
1351
+ { name: 'Safe prompt wrapper', patterns: SAFETY_CRITICAL_TEST_GLOBS.slice(8, 10) },
1352
+ { name: 'Crisis handling', patterns: SAFETY_CRITICAL_TEST_GLOBS.slice(10, 12) },
1353
+ ];
1354
+ for (const category of categories) {
1355
+ let categoryHasTests = false;
1356
+ for (const pattern of category.patterns) {
1357
+ try {
1358
+ const matches = await glob(pattern, {
1359
+ cwd: projectRoot,
1360
+ absolute: false,
1361
+ });
1362
+ if (matches.length > 0) {
1363
+ categoryHasTests = true;
1364
+ foundTests.push(...matches);
1365
+ }
1366
+ }
1367
+ catch {
1368
+ // Pattern error, treat as no matches
1369
+ }
1370
+ }
1371
+ if (!categoryHasTests) {
1372
+ missingTests.push(`${category.name}: ${category.patterns.join(', ')}`);
1373
+ }
1374
+ }
1375
+ const valid = missingTests.length === 0;
1376
+ return {
1377
+ valid,
1378
+ missingTests,
1379
+ foundTests: [...new Set(foundTests)],
1380
+ error: valid ? undefined : `Missing safety-critical tests: ${missingTests.join('; ')}`,
1381
+ };
1382
+ }