@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,427 @@
1
+ /**
2
+ * Micro-Worktree Operations
3
+ *
4
+ * Race-safe micro-worktree isolation pattern extracted from wu-create.mjs (WU-1262).
5
+ * Provides shared infrastructure for commands that need to modify main branch
6
+ * atomically without switching checkout.
7
+ *
8
+ * Part of WU-1262: Race-safe WU creation using micro-worktrees
9
+ * Extended in WU-1274: Add wu:edit command for spec-only changes
10
+ * Extended in WU-1439: Migrate initiative:create and wu:create to shared helper
11
+ *
12
+ * Pattern:
13
+ * 1. Create temp branch without switching main checkout
14
+ * 2. Create micro-worktree in /tmp pointing to temp branch
15
+ * 3. Perform operations in micro-worktree
16
+ * 4. FF-only merge temp branch to main (retry with rebase if main moved)
17
+ * 5. Push to origin
18
+ * 6. Cleanup (always, even on failure)
19
+ *
20
+ * Benefits:
21
+ * - Main checkout never switches branches (no impact on other agents)
22
+ * - Race conditions handled via rebase+retry (up to MAX_MERGE_RETRIES attempts)
23
+ * - Cleanup guaranteed even on failure
24
+ *
25
+ * Consumers:
26
+ * @see {@link tools/wu-create.mjs} - WU creation (WU-1262, WU-1439)
27
+ * @see {@link tools/wu-edit.mjs} - Spec edits (WU-1274)
28
+ * @see {@link tools/initiative-create.mjs} - Initiative creation (WU-1439)
29
+ */
30
+ import { getGitForCwd, createGitForPath } from './git-adapter.js';
31
+ import { existsSync, rmSync, mkdtempSync } from 'node:fs';
32
+ import { execSync } from 'node:child_process';
33
+ import { tmpdir } from 'node:os';
34
+ import { join } from 'node:path';
35
+ import { BRANCHES, REMOTES, GIT_REFS, PKG_MANAGER, SCRIPTS, PRETTIER_FLAGS, STDIO_MODES, } from './wu-constants.js';
36
+ /**
37
+ * Maximum retry attempts for ff-only merge when main moves
38
+ *
39
+ * This handles race conditions when multiple agents run wu:create or wu:edit
40
+ * concurrently. Each retry fetches latest main and rebases.
41
+ */
42
+ export const MAX_MERGE_RETRIES = 3;
43
+ /**
44
+ * Default log prefix for micro-worktree operations
45
+ *
46
+ * Extracted to constant to satisfy sonarjs/no-duplicate-string rule.
47
+ */
48
+ export const DEFAULT_LOG_PREFIX = '[micro-wt]';
49
+ /**
50
+ * Temp branch prefix for micro-worktree operations
51
+ *
52
+ * @param {string} operation - Operation name (e.g., 'wu-create', 'wu-edit')
53
+ * @param {string} id - WU ID (e.g., 'wu-123')
54
+ * @returns {string} Temp branch name (e.g., 'tmp/wu-create/wu-123')
55
+ */
56
+ export function getTempBranchName(operation, id) {
57
+ return `${BRANCHES.TEMP_PREFIX}${operation}/${id.toLowerCase()}`;
58
+ }
59
+ /**
60
+ * Create micro-worktree in /tmp directory
61
+ *
62
+ * @param {string} prefix - Directory prefix (e.g., 'wu-create-', 'wu-edit-')
63
+ * @returns {string} Path to created micro-worktree directory
64
+ */
65
+ export function createMicroWorktreeDir(prefix) {
66
+ return mkdtempSync(join(tmpdir(), prefix));
67
+ }
68
+ /**
69
+ * Parse git worktree list output to find worktrees by branch
70
+ *
71
+ * WU-2237: Helper to parse porcelain format output from `git worktree list --porcelain`
72
+ *
73
+ * @param {string} worktreeListOutput - Output from git worktree list --porcelain
74
+ * @param {string} branchName - Branch name to search for (e.g., 'tmp/wu-create/wu-123')
75
+ * @returns {string|null} Worktree path if found, null otherwise
76
+ */
77
+ export function findWorktreeByBranch(worktreeListOutput, branchName) {
78
+ const branchRef = `refs/heads/${branchName}`;
79
+ const lines = worktreeListOutput.split('\n');
80
+ let currentWorktreePath = null;
81
+ for (const line of lines) {
82
+ if (line.startsWith('worktree ')) {
83
+ currentWorktreePath = line.substring('worktree '.length);
84
+ }
85
+ else if (line.startsWith('branch ') && line.substring('branch '.length) === branchRef) {
86
+ return currentWorktreePath;
87
+ }
88
+ else if (line === '') {
89
+ currentWorktreePath = null;
90
+ }
91
+ }
92
+ return null;
93
+ }
94
+ /**
95
+ * Clean up orphaned micro-worktree and temp branch from a previous interrupted operation
96
+ *
97
+ * WU-2237: Before creating a new micro-worktree, detect and clean any existing temp
98
+ * branch/worktree for the same operation+WU ID. This handles scenarios where:
99
+ * - A previous wu:create/wu:edit was interrupted (timeout/crash)
100
+ * - The temp branch and /tmp worktree were left behind
101
+ * - A subsequent operation would fail with 'branch already exists'
102
+ *
103
+ * This function is idempotent - safe to call even when no orphans exist.
104
+ *
105
+ * @param {string} operation - Operation name (e.g., 'wu-create', 'wu-edit')
106
+ * @param {string} id - WU ID (e.g., 'WU-123')
107
+ * @param {Object} gitAdapter - GitAdapter instance to use (for testability)
108
+ * @param {string} logPrefix - Log prefix for console output
109
+ * @returns {Promise<{cleanedWorktree: boolean, cleanedBranch: boolean}>} Cleanup status
110
+ */
111
+ export async function cleanupOrphanedMicroWorktree(operation, id, gitAdapter, logPrefix = DEFAULT_LOG_PREFIX) {
112
+ const tempBranchName = getTempBranchName(operation, id);
113
+ let cleanedWorktree = false;
114
+ let cleanedBranch = false;
115
+ // Step 1: Check git worktree list for any worktree on this temp branch
116
+ try {
117
+ const worktreeListOutput = await gitAdapter.worktreeList();
118
+ const orphanWorktreePath = findWorktreeByBranch(worktreeListOutput, tempBranchName);
119
+ if (orphanWorktreePath) {
120
+ console.log(`${logPrefix} Found orphaned worktree for ${tempBranchName}: ${orphanWorktreePath}`);
121
+ try {
122
+ await gitAdapter.worktreeRemove(orphanWorktreePath, { force: true });
123
+ console.log(`${logPrefix} ✅ Removed orphaned worktree: ${orphanWorktreePath}`);
124
+ cleanedWorktree = true;
125
+ }
126
+ catch (err) {
127
+ console.warn(`${logPrefix} ⚠️ Could not remove orphaned worktree: ${err.message}`);
128
+ // Try filesystem cleanup as fallback
129
+ tryFilesystemCleanup(orphanWorktreePath);
130
+ cleanedWorktree = true;
131
+ }
132
+ }
133
+ }
134
+ catch (err) {
135
+ console.warn(`${logPrefix} ⚠️ Could not check worktree list: ${err.message}`);
136
+ }
137
+ // Step 2: Check if the temp branch exists and delete it
138
+ try {
139
+ const branchExists = await gitAdapter.branchExists(tempBranchName);
140
+ if (branchExists) {
141
+ console.log(`${logPrefix} Found orphaned temp branch: ${tempBranchName}`);
142
+ await gitAdapter.deleteBranch(tempBranchName, { force: true });
143
+ console.log(`${logPrefix} ✅ Deleted orphaned temp branch: ${tempBranchName}`);
144
+ cleanedBranch = true;
145
+ }
146
+ }
147
+ catch (err) {
148
+ console.warn(`${logPrefix} ⚠️ Could not delete orphaned branch: ${err.message}`);
149
+ }
150
+ return { cleanedWorktree, cleanedBranch };
151
+ }
152
+ /**
153
+ * Try to remove a worktree path via filesystem as fallback
154
+ *
155
+ * WU-2237: Extracted helper to reduce cognitive complexity.
156
+ *
157
+ * @param {string} worktreePath - Path to remove
158
+ */
159
+ function tryFilesystemCleanup(worktreePath) {
160
+ try {
161
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool with validated worktree path
162
+ if (existsSync(worktreePath)) {
163
+ rmSync(worktreePath, { recursive: true, force: true });
164
+ }
165
+ }
166
+ catch {
167
+ // Ignore filesystem cleanup errors
168
+ }
169
+ }
170
+ /**
171
+ * Remove a worktree using git, with filesystem fallback
172
+ *
173
+ * WU-2237: Extracted helper to reduce cognitive complexity.
174
+ *
175
+ * @param {Object} gitAdapter - Git adapter instance
176
+ * @param {string} worktreePath - Path to worktree
177
+ * @param {string} logPrefix - Log prefix
178
+ * @param {string} [contextLabel] - Optional label for logging (e.g., 'registered')
179
+ */
180
+ async function removeWorktreeSafe(gitAdapter, worktreePath, logPrefix, contextLabel = '') {
181
+ const label = contextLabel ? ` ${contextLabel}` : '';
182
+ try {
183
+ await gitAdapter.worktreeRemove(worktreePath, { force: true });
184
+ if (contextLabel) {
185
+ console.log(`${logPrefix} ✅ Removed${label} worktree: ${worktreePath}`);
186
+ }
187
+ }
188
+ catch (err) {
189
+ console.warn(`${logPrefix} ⚠️ Could not remove${label} worktree: ${err.message}`);
190
+ tryFilesystemCleanup(worktreePath);
191
+ }
192
+ }
193
+ /**
194
+ * Cleanup micro-worktree and temp branch
195
+ *
196
+ * Runs even on failure to prevent orphaned resources.
197
+ * Safe to call multiple times (idempotent).
198
+ *
199
+ * WU-2237: Enhanced to also check git worktree list for registered worktrees
200
+ * on the temp branch, in case the worktree path differs from what was expected.
201
+ *
202
+ * @param {string} worktreePath - Path to micro-worktree
203
+ * @param {string} branchName - Temp branch name
204
+ * @param {string} logPrefix - Log prefix for console output
205
+ */
206
+ export async function cleanupMicroWorktree(worktreePath, branchName, logPrefix = DEFAULT_LOG_PREFIX) {
207
+ console.log(`${logPrefix} Cleaning up micro-worktree...`);
208
+ const mainGit = getGitForCwd();
209
+ // Remove the known worktree path first (must be done before deleting branch)
210
+ // eslint-disable-next-line security/detect-non-literal-fs-filename -- CLI tool with validated worktree path
211
+ if (existsSync(worktreePath)) {
212
+ await removeWorktreeSafe(mainGit, worktreePath, logPrefix);
213
+ }
214
+ // WU-2237: Also check git worktree list for any registered worktrees on this branch
215
+ await cleanupRegisteredWorktreeForBranch(mainGit, branchName, worktreePath, logPrefix);
216
+ // Delete temp branch
217
+ await deleteBranchSafe(mainGit, branchName, logPrefix);
218
+ console.log(`${logPrefix} ✅ Cleanup complete`);
219
+ }
220
+ /**
221
+ * Clean up any registered worktree for a branch that differs from the expected path
222
+ *
223
+ * WU-2237: Extracted helper to reduce cognitive complexity.
224
+ *
225
+ * @param {Object} gitAdapter - Git adapter instance
226
+ * @param {string} branchName - Branch name to search for
227
+ * @param {string} expectedPath - Expected worktree path (skip if matches)
228
+ * @param {string} logPrefix - Log prefix
229
+ */
230
+ async function cleanupRegisteredWorktreeForBranch(gitAdapter, branchName, expectedPath, logPrefix) {
231
+ try {
232
+ const worktreeListOutput = await gitAdapter.worktreeList();
233
+ const registeredPath = findWorktreeByBranch(worktreeListOutput, branchName);
234
+ if (registeredPath && registeredPath !== expectedPath) {
235
+ console.log(`${logPrefix} Found additional registered worktree: ${registeredPath}`);
236
+ await removeWorktreeSafe(gitAdapter, registeredPath, logPrefix, 'registered');
237
+ }
238
+ }
239
+ catch (err) {
240
+ console.warn(`${logPrefix} ⚠️ Could not check worktree list: ${err.message}`);
241
+ }
242
+ }
243
+ /**
244
+ * Delete a branch safely, ignoring errors
245
+ *
246
+ * WU-2237: Extracted helper to reduce cognitive complexity.
247
+ *
248
+ * @param {Object} gitAdapter - Git adapter instance
249
+ * @param {string} branchName - Branch to delete
250
+ * @param {string} logPrefix - Log prefix
251
+ */
252
+ async function deleteBranchSafe(gitAdapter, branchName, logPrefix) {
253
+ try {
254
+ const branchExists = await gitAdapter.branchExists(branchName);
255
+ if (branchExists) {
256
+ await gitAdapter.deleteBranch(branchName, { force: true });
257
+ }
258
+ }
259
+ catch (err) {
260
+ console.warn(`${logPrefix} ⚠️ Could not delete branch: ${err.message}`);
261
+ }
262
+ }
263
+ /**
264
+ * Stage changes including deletions in micro-worktree
265
+ *
266
+ * WU-1813: Uses addWithDeletions to properly stage tracked file deletions.
267
+ * This replaces the previous pattern of using gitWorktree.add(files) which
268
+ * could miss deletions when files were removed.
269
+ *
270
+ * @param {Object} gitWorktree - GitAdapter instance for the worktree
271
+ * @param {string[]|undefined} files - Files to stage (undefined/empty = stage all)
272
+ * @returns {Promise<void>}
273
+ */
274
+ export async function stageChangesWithDeletions(gitWorktree, files) {
275
+ // Normalise undefined/null to empty array for addWithDeletions
276
+ const filesToStage = files || [];
277
+ await gitWorktree.addWithDeletions(filesToStage);
278
+ }
279
+ /**
280
+ * Format files using prettier before committing
281
+ *
282
+ * WU-1435: Ensures committed files pass format gates.
283
+ * Runs prettier --write on specified files within the micro-worktree.
284
+ *
285
+ * @param {string[]} files - Relative file paths to format
286
+ * @param {string} worktreePath - Path to the micro-worktree
287
+ * @param {string} logPrefix - Log prefix for console output
288
+ */
289
+ export async function formatFiles(files, worktreePath, logPrefix = DEFAULT_LOG_PREFIX) {
290
+ if (!files || files.length === 0) {
291
+ return;
292
+ }
293
+ console.log(`${logPrefix} Formatting ${files.length} file(s)...`);
294
+ // Build absolute paths within the worktree
295
+ const absolutePaths = files.map((f) => join(worktreePath, f));
296
+ const pathArgs = absolutePaths.map((p) => JSON.stringify(p)).join(' ');
297
+ try {
298
+ execSync(`${PKG_MANAGER} ${SCRIPTS.PRETTIER} ${PRETTIER_FLAGS.WRITE} ${pathArgs}`, {
299
+ encoding: 'utf-8',
300
+ stdio: STDIO_MODES.PIPE,
301
+ cwd: worktreePath,
302
+ });
303
+ console.log(`${logPrefix} ✅ Files formatted`);
304
+ }
305
+ catch (err) {
306
+ // Log warning but don't fail - some files may not need formatting
307
+ console.warn(`${logPrefix} ⚠️ Formatting warning: ${err.message}`);
308
+ }
309
+ }
310
+ /**
311
+ * Merge temp branch to main with ff-only and retry logic
312
+ *
313
+ * Handles race conditions when main branch advances between operation start
314
+ * and merge attempt. Retries with rebase up to MAX_MERGE_RETRIES times.
315
+ *
316
+ * @param {string} tempBranchName - Temp branch to merge
317
+ * @param {string} microWorktreePath - Path to micro-worktree (for rebase)
318
+ * @param {string} logPrefix - Log prefix for console output
319
+ * @throws {Error} If merge fails after all retries
320
+ */
321
+ export async function mergeWithRetry(tempBranchName, microWorktreePath, logPrefix = DEFAULT_LOG_PREFIX) {
322
+ const gitWorktree = createGitForPath(microWorktreePath);
323
+ const mainGit = getGitForCwd();
324
+ for (let attempt = 1; attempt <= MAX_MERGE_RETRIES; attempt++) {
325
+ try {
326
+ console.log(`${logPrefix} Merging to main (attempt ${attempt}/${MAX_MERGE_RETRIES})...`);
327
+ await mainGit.merge(tempBranchName, { ffOnly: true });
328
+ console.log(`${logPrefix} ✅ Merged to main`);
329
+ return;
330
+ }
331
+ catch (mergeErr) {
332
+ if (attempt < MAX_MERGE_RETRIES) {
333
+ console.log(`${logPrefix} ⚠️ FF-only merge failed (main moved). Rebasing...`);
334
+ // Fetch latest main and rebase temp branch
335
+ await mainGit.fetch(REMOTES.ORIGIN, BRANCHES.MAIN);
336
+ await mainGit.merge(`${REMOTES.ORIGIN}/${BRANCHES.MAIN}`, { ffOnly: true }); // Update local main
337
+ await gitWorktree.rebase(BRANCHES.MAIN);
338
+ }
339
+ else {
340
+ throw new Error(`FF-only merge failed after ${MAX_MERGE_RETRIES} attempts. ` +
341
+ `Main branch may have significant divergence.\n` +
342
+ `Error: ${mergeErr.message}`);
343
+ }
344
+ }
345
+ }
346
+ }
347
+ /**
348
+ * Execute an operation in a micro-worktree with full isolation
349
+ *
350
+ * This is the main entry point for micro-worktree operations.
351
+ * Handles the full lifecycle: create temp branch, create worktree,
352
+ * execute operation, merge, push, and cleanup.
353
+ *
354
+ * WU-1435: Added pushOnly option to keep local main pristine.
355
+ * WU-2237: Added pre-creation cleanup of orphaned temp branches/worktrees.
356
+ *
357
+ * @param {Object} options - Options for the operation
358
+ * @param {string} options.operation - Operation name (e.g., 'wu-create', 'wu-edit')
359
+ * @param {string} options.id - WU ID (e.g., 'WU-123')
360
+ * @param {string} options.logPrefix - Log prefix for console output
361
+ * @param {boolean} [options.pushOnly=false] - Skip local main merge, push directly to origin/main
362
+ * @param {Function} options.execute - Async function to execute in micro-worktree
363
+ * Receives: { worktreePath: string, gitWorktree: GitAdapter }
364
+ * Should return: { commitMessage: string, files: string[] }
365
+ * @returns {Promise<Object>} Result with ref property for worktree creation
366
+ * @throws {Error} If any step fails (cleanup still runs)
367
+ */
368
+ export async function withMicroWorktree(options) {
369
+ const { operation, id, logPrefix = `[${operation}]`, execute, pushOnly = false } = options;
370
+ const mainGit = getGitForCwd();
371
+ // WU-2237: Clean up any orphaned temp branch/worktree from previous interrupted operations
372
+ // This makes the operation idempotent - a retry after crash/timeout will succeed
373
+ await cleanupOrphanedMicroWorktree(operation, id, mainGit, logPrefix);
374
+ const tempBranchName = getTempBranchName(operation, id);
375
+ const microWorktreePath = createMicroWorktreeDir(`${operation}-`);
376
+ console.log(`${logPrefix} Using micro-worktree isolation (WU-1262)`);
377
+ console.log(`${logPrefix} Temp branch: ${tempBranchName}`);
378
+ console.log(`${logPrefix} Micro-worktree: ${microWorktreePath}`);
379
+ if (pushOnly) {
380
+ console.log(`${logPrefix} Push-only mode: local main will not be modified (WU-1435)`);
381
+ }
382
+ try {
383
+ // Step 1: Create temp branch without switching
384
+ console.log(`${logPrefix} Creating temp branch...`);
385
+ await mainGit.createBranchNoCheckout(tempBranchName, BRANCHES.MAIN);
386
+ // Step 2: Create micro-worktree pointing to temp branch
387
+ console.log(`${logPrefix} Creating micro-worktree...`);
388
+ await mainGit.worktreeAddExisting(microWorktreePath, tempBranchName);
389
+ // Step 3: Execute the operation in micro-worktree
390
+ const gitWorktree = createGitForPath(microWorktreePath);
391
+ const result = await execute({ worktreePath: microWorktreePath, gitWorktree });
392
+ // Step 4: Format files before committing (WU-1435)
393
+ await formatFiles(result.files, microWorktreePath, logPrefix);
394
+ // Step 5: Stage and commit in micro-worktree
395
+ // WU-1813: Use stageChangesWithDeletions to properly handle file deletions
396
+ console.log(`${logPrefix} Staging changes (including deletions)...`);
397
+ await stageChangesWithDeletions(gitWorktree, result.files);
398
+ console.log(`${logPrefix} Committing in micro-worktree...`);
399
+ await gitWorktree.commit(result.commitMessage);
400
+ console.log(`${logPrefix} ✅ Committed: ${result.commitMessage}`);
401
+ // Step 6: Push to origin (different paths for pushOnly vs standard)
402
+ if (pushOnly) {
403
+ // WU-1435: Push directly to origin/main without touching local main
404
+ console.log(`${logPrefix} Pushing directly to ${REMOTES.ORIGIN}/${BRANCHES.MAIN} (push-only)...`);
405
+ await gitWorktree.pushRefspec(REMOTES.ORIGIN, tempBranchName, BRANCHES.MAIN);
406
+ console.log(`${logPrefix} ✅ Pushed to ${REMOTES.ORIGIN}/${BRANCHES.MAIN}`);
407
+ // Fetch to update remote tracking ref (FETCH_HEAD)
408
+ console.log(`${logPrefix} Fetching ${REMOTES.ORIGIN}/${BRANCHES.MAIN}...`);
409
+ await mainGit.fetch(REMOTES.ORIGIN, BRANCHES.MAIN);
410
+ console.log(`${logPrefix} ✅ Fetched ${REMOTES.ORIGIN}/${BRANCHES.MAIN}`);
411
+ // Return FETCH_HEAD as ref for worktree creation
412
+ return { ...result, ref: GIT_REFS.FETCH_HEAD };
413
+ }
414
+ else {
415
+ // Standard path: merge to local main, then push
416
+ await mergeWithRetry(tempBranchName, microWorktreePath, logPrefix);
417
+ console.log(`${logPrefix} Pushing to ${REMOTES.ORIGIN}/${BRANCHES.MAIN}...`);
418
+ await mainGit.push(REMOTES.ORIGIN, BRANCHES.MAIN);
419
+ console.log(`${logPrefix} ✅ Pushed to ${REMOTES.ORIGIN}/${BRANCHES.MAIN}`);
420
+ return { ...result, ref: BRANCHES.MAIN };
421
+ }
422
+ }
423
+ finally {
424
+ // Cleanup (always runs)
425
+ await cleanupMicroWorktree(microWorktreePath, tempBranchName, logPrefix);
426
+ }
427
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @file migration-deployer.mjs
3
+ * @description Migration deployment utilities for Supabase schema sync
4
+ * WU-1983: Sync production schema and establish migration deployment workflow
5
+ *
6
+ * Provides:
7
+ * - Local migration file discovery
8
+ * - Migration name extraction (timestamp + name)
9
+ * - Integration point for MCP-based deployment
10
+ */
11
+ /**
12
+ * Default migrations directory path (relative to repo root)
13
+ */
14
+ export declare const MIGRATIONS_DIR = "supabase/supabase/migrations";
15
+ /**
16
+ * Extract migration info from filename
17
+ * @param {string} filename - Migration filename (e.g., '20251224125733_patient_documents_storage.sql')
18
+ * @returns {{ timestamp: string, name: string, fullName: string } | null}
19
+ */
20
+ export declare function parseMigrationFilename(filename: any): {
21
+ timestamp: string;
22
+ name: string;
23
+ fullName: string;
24
+ };
25
+ /**
26
+ * Discover local migration files
27
+ * @param {string} baseDir - Base directory (repo root)
28
+ * @returns {{ files: Array<{ filename: string, timestamp: string, name: string, fullName: string, path: string }>, errors: string[] }}
29
+ */
30
+ export declare function discoverLocalMigrations(baseDir: any): {
31
+ files: any[];
32
+ errors: any[];
33
+ };
34
+ /**
35
+ * Read migration SQL content
36
+ * @param {string} migrationPath - Full path to migration file
37
+ * @returns {string} SQL content
38
+ */
39
+ export declare function readMigrationContent(migrationPath: any): string;
40
+ /**
41
+ * Check if WU code_paths includes Supabase migrations
42
+ * @param {string[]} codePaths - Array of code paths from WU YAML
43
+ * @returns {boolean} True if migrations are in scope
44
+ */
45
+ export declare function hasMigrationChanges(codePaths: any): boolean;
46
+ /**
47
+ * Compare local migrations with production (for drift detection)
48
+ * @param {Array<{ fullName: string }>} localMigrations - Local migration list
49
+ * @param {Array<{ name: string }>} productionMigrations - Production migration list (from MCP)
50
+ * @returns {{ missing: string[], extra: string[], synced: boolean }}
51
+ */
52
+ export declare function compareMigrations(localMigrations: any, productionMigrations: any): {
53
+ missing: any;
54
+ extra: any;
55
+ synced: boolean;
56
+ };
57
+ /**
58
+ * Format migration deployment report
59
+ * @param {{ missing: string[], extra: string[], synced: boolean }} comparison
60
+ * @returns {string} Formatted report
61
+ */
62
+ export declare function formatMigrationReport(comparison: any): string;
63
+ /**
64
+ * Build MCP migration deployment command (for documentation/agents)
65
+ * @param {string} migrationName - Full migration name (e.g., '20251224125733_patient_documents_storage')
66
+ * @param {string} sql - Migration SQL content
67
+ * @returns {string} MCP command description
68
+ */
69
+ export declare function buildMCPDeploymentHint(migrationName: any, sql: any): string;
@@ -0,0 +1,151 @@
1
+ /**
2
+ * @file migration-deployer.mjs
3
+ * @description Migration deployment utilities for Supabase schema sync
4
+ * WU-1983: Sync production schema and establish migration deployment workflow
5
+ *
6
+ * Provides:
7
+ * - Local migration file discovery
8
+ * - Migration name extraction (timestamp + name)
9
+ * - Integration point for MCP-based deployment
10
+ */
11
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
12
+ import path from 'node:path';
13
+ /**
14
+ * Default migrations directory path (relative to repo root)
15
+ */
16
+ export const MIGRATIONS_DIR = 'supabase/supabase/migrations';
17
+ /**
18
+ * Migration file pattern (YYYYMMDDHHMMSS_name.sql)
19
+ * @type {RegExp}
20
+ */
21
+ const MIGRATION_FILE_PATTERN = /^(\d{14})_(.+)\.sql$/;
22
+ /**
23
+ * Extract migration info from filename
24
+ * @param {string} filename - Migration filename (e.g., '20251224125733_patient_documents_storage.sql')
25
+ * @returns {{ timestamp: string, name: string, fullName: string } | null}
26
+ */
27
+ export function parseMigrationFilename(filename) {
28
+ const match = MIGRATION_FILE_PATTERN.exec(filename);
29
+ if (!match)
30
+ return null;
31
+ return {
32
+ timestamp: match[1],
33
+ name: match[2],
34
+ fullName: `${match[1]}_${match[2]}`,
35
+ };
36
+ }
37
+ /**
38
+ * Discover local migration files
39
+ * @param {string} baseDir - Base directory (repo root)
40
+ * @returns {{ files: Array<{ filename: string, timestamp: string, name: string, fullName: string, path: string }>, errors: string[] }}
41
+ */
42
+ export function discoverLocalMigrations(baseDir) {
43
+ const migrationsPath = path.join(baseDir, MIGRATIONS_DIR);
44
+ const errors = [];
45
+ const files = [];
46
+ if (!existsSync(migrationsPath)) {
47
+ errors.push(`Migrations directory not found: ${migrationsPath}`);
48
+ return { files, errors };
49
+ }
50
+ try {
51
+ const entries = readdirSync(migrationsPath, { withFileTypes: true });
52
+ for (const entry of entries) {
53
+ if (!entry.isFile() || !entry.name.endsWith('.sql'))
54
+ continue;
55
+ const parsed = parseMigrationFilename(entry.name);
56
+ if (!parsed) {
57
+ errors.push(`Invalid migration filename format: ${entry.name}`);
58
+ continue;
59
+ }
60
+ files.push({
61
+ filename: entry.name,
62
+ timestamp: parsed.timestamp,
63
+ name: parsed.name,
64
+ fullName: parsed.fullName,
65
+ path: path.join(migrationsPath, entry.name),
66
+ });
67
+ }
68
+ // Sort by timestamp (ascending)
69
+ files.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
70
+ }
71
+ catch (err) {
72
+ errors.push(`Error reading migrations directory: ${err.message}`);
73
+ }
74
+ return { files, errors };
75
+ }
76
+ /**
77
+ * Read migration SQL content
78
+ * @param {string} migrationPath - Full path to migration file
79
+ * @returns {string} SQL content
80
+ */
81
+ export function readMigrationContent(migrationPath) {
82
+ return readFileSync(migrationPath, 'utf8');
83
+ }
84
+ /**
85
+ * Check if WU code_paths includes Supabase migrations
86
+ * @param {string[]} codePaths - Array of code paths from WU YAML
87
+ * @returns {boolean} True if migrations are in scope
88
+ */
89
+ export function hasMigrationChanges(codePaths) {
90
+ if (!Array.isArray(codePaths))
91
+ return false;
92
+ const migrationPatterns = ['supabase/', 'supabase/supabase/migrations/', MIGRATIONS_DIR];
93
+ return codePaths.some((codePath) => migrationPatterns.some((pattern) => codePath.startsWith(pattern) || codePath === pattern.slice(0, -1)));
94
+ }
95
+ /**
96
+ * Compare local migrations with production (for drift detection)
97
+ * @param {Array<{ fullName: string }>} localMigrations - Local migration list
98
+ * @param {Array<{ name: string }>} productionMigrations - Production migration list (from MCP)
99
+ * @returns {{ missing: string[], extra: string[], synced: boolean }}
100
+ */
101
+ export function compareMigrations(localMigrations, productionMigrations) {
102
+ const localNames = new Set(localMigrations.map((m) => m.fullName));
103
+ const prodNames = new Set(productionMigrations.map((m) => m.name));
104
+ // Migrations in local but not in production
105
+ const missing = localMigrations.filter((m) => !prodNames.has(m.fullName)).map((m) => m.fullName);
106
+ // Migrations in production but not in local (unusual but possible)
107
+ const extra = productionMigrations.filter((m) => !localNames.has(m.name)).map((m) => m.name);
108
+ return {
109
+ missing,
110
+ extra,
111
+ synced: missing.length === 0 && extra.length === 0,
112
+ };
113
+ }
114
+ /**
115
+ * Format migration deployment report
116
+ * @param {{ missing: string[], extra: string[], synced: boolean }} comparison
117
+ * @returns {string} Formatted report
118
+ */
119
+ export function formatMigrationReport(comparison) {
120
+ const lines = [];
121
+ if (comparison.synced) {
122
+ lines.push('Migrations are in sync between local and production.');
123
+ return lines.join('\n');
124
+ }
125
+ if (comparison.missing.length > 0) {
126
+ lines.push('Migrations missing from production:');
127
+ comparison.missing.forEach((name) => lines.push(` - ${name}`));
128
+ lines.push('');
129
+ }
130
+ if (comparison.extra.length > 0) {
131
+ lines.push('Migrations in production but not local (unexpected):');
132
+ comparison.extra.forEach((name) => lines.push(` - ${name}`));
133
+ lines.push('');
134
+ }
135
+ return lines.join('\n');
136
+ }
137
+ /**
138
+ * Build MCP migration deployment command (for documentation/agents)
139
+ * @param {string} migrationName - Full migration name (e.g., '20251224125733_patient_documents_storage')
140
+ * @param {string} sql - Migration SQL content
141
+ * @returns {string} MCP command description
142
+ */
143
+ export function buildMCPDeploymentHint(migrationName, sql) {
144
+ return `To deploy ${migrationName} to production:
145
+
146
+ Use mcp__supabase__apply_migration with:
147
+ - name: "${migrationName}"
148
+ - sql: <content of migration file>
149
+
150
+ Or use mcp__supabase__execute_sql for individual statements.`;
151
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Orchestration Advisory Loader
3
+ *
4
+ * Pure JavaScript implementation of mandatory agent advisory.
5
+ * Uses minimatch for glob pattern matching (same as TypeScript version).
6
+ *
7
+ * @module orchestration-advisory-loader
8
+ * @see {@link ./orchestration-advisory.mjs} - TypeScript version for tests
9
+ * @see {@link ./domain/orchestration.constants.mjs} - Pattern definitions
10
+ */
11
+ /**
12
+ * Emit mandatory agent advisory based on code paths.
13
+ *
14
+ * @param {string[]} codePaths - Array of file paths
15
+ * @param {string} wuId - Work Unit ID
16
+ */
17
+ export declare function emitMandatoryAgentAdvisory(codePaths: any, wuId: any): void;
18
+ /**
19
+ * Check mandatory agent compliance.
20
+ *
21
+ * @param {string[]} codePaths - Array of file paths
22
+ * @param {string} _wuId - Work Unit ID (reserved for future telemetry lookup)
23
+ * @returns {{compliant: boolean, missing: string[]}}
24
+ */
25
+ export declare function checkMandatoryAgentsCompliance(codePaths: any, _wuId: any): {
26
+ compliant: boolean;
27
+ missing: unknown[];
28
+ };