@lumenflow/cli 3.1.3 → 3.2.1

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 (267) hide show
  1. package/dist/agent-issues-query.js.map +1 -0
  2. package/dist/agent-log-issue.js.map +1 -0
  3. package/dist/agent-session-end.js.map +1 -0
  4. package/dist/agent-session.js.map +1 -0
  5. package/dist/backlog-prune.js.map +1 -0
  6. package/dist/cli-entry-point.js +139 -0
  7. package/dist/cli-entry-point.js.map +1 -0
  8. package/dist/commands/integrate.js.map +1 -0
  9. package/dist/commands.js.map +1 -0
  10. package/dist/config-get.js.map +1 -0
  11. package/dist/config-set.js.map +1 -0
  12. package/dist/constants.js +98 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/delegation-list.js.map +1 -0
  15. package/dist/deps-add.js +259 -0
  16. package/dist/deps-add.js.map +1 -0
  17. package/dist/deps-remove.js +105 -0
  18. package/dist/deps-remove.js.map +1 -0
  19. package/dist/docs-sync.js.map +1 -0
  20. package/dist/doctor.js.map +1 -0
  21. package/dist/file-delete.js.map +1 -0
  22. package/dist/file-edit.js.map +1 -0
  23. package/dist/file-read.js.map +1 -0
  24. package/dist/file-write.js.map +1 -0
  25. package/dist/flow-bottlenecks.js.map +1 -0
  26. package/dist/flow-report.js.map +1 -0
  27. package/dist/formatters.js +151 -0
  28. package/dist/formatters.js.map +1 -0
  29. package/dist/gate-defaults.js +137 -0
  30. package/dist/gate-defaults.js.map +1 -0
  31. package/dist/gate-registry.js +73 -0
  32. package/dist/gate-registry.js.map +1 -0
  33. package/dist/gates-graceful-degradation.js +153 -0
  34. package/dist/gates-graceful-degradation.js.map +1 -0
  35. package/dist/gates-plan-resolvers.js +190 -0
  36. package/dist/gates-plan-resolvers.js.map +1 -0
  37. package/dist/gates-runners.js +545 -0
  38. package/dist/gates-runners.js.map +1 -0
  39. package/dist/gates-types.js +4 -0
  40. package/dist/gates-types.js.map +1 -0
  41. package/dist/gates-utils.js +333 -0
  42. package/dist/gates-utils.js.map +1 -0
  43. package/dist/gates.js.map +1 -0
  44. package/dist/git-branch.js.map +1 -0
  45. package/dist/git-diff.js.map +1 -0
  46. package/dist/git-log.js.map +1 -0
  47. package/dist/git-status.js.map +1 -0
  48. package/dist/guard-locked.js +172 -0
  49. package/dist/guard-locked.js.map +1 -0
  50. package/dist/guard-main-branch.js +217 -0
  51. package/dist/guard-main-branch.js.map +1 -0
  52. package/dist/guard-worktree-commit.js +163 -0
  53. package/dist/guard-worktree-commit.js.map +1 -0
  54. package/dist/hooks/auto-checkpoint-utils.js +54 -0
  55. package/dist/hooks/auto-checkpoint-utils.js.map +1 -0
  56. package/dist/hooks/enforcement-checks.js +399 -0
  57. package/dist/hooks/enforcement-checks.js.map +1 -0
  58. package/dist/hooks/enforcement-generator.js +139 -0
  59. package/dist/hooks/enforcement-generator.js.map +1 -0
  60. package/dist/hooks/enforcement-sync.js +380 -0
  61. package/dist/hooks/enforcement-sync.js.map +1 -0
  62. package/dist/hooks/generators/auto-checkpoint.js +125 -0
  63. package/dist/hooks/generators/auto-checkpoint.js.map +1 -0
  64. package/dist/hooks/generators/enforce-worktree.js +190 -0
  65. package/dist/hooks/generators/enforce-worktree.js.map +1 -0
  66. package/dist/hooks/generators/index.js +18 -0
  67. package/dist/hooks/generators/index.js.map +1 -0
  68. package/dist/hooks/generators/pre-compact-checkpoint.js +136 -0
  69. package/dist/hooks/generators/pre-compact-checkpoint.js.map +1 -0
  70. package/dist/hooks/generators/require-wu.js +117 -0
  71. package/dist/hooks/generators/require-wu.js.map +1 -0
  72. package/dist/hooks/generators/session-start-recovery.js +103 -0
  73. package/dist/hooks/generators/session-start-recovery.js.map +1 -0
  74. package/dist/hooks/generators/signal-utils.js +54 -0
  75. package/dist/hooks/generators/signal-utils.js.map +1 -0
  76. package/dist/hooks/generators/warn-incomplete.js +67 -0
  77. package/dist/hooks/generators/warn-incomplete.js.map +1 -0
  78. package/dist/hooks/index.js +10 -0
  79. package/dist/hooks/index.js.map +1 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/init-detection.js +232 -0
  82. package/dist/init-detection.js.map +1 -0
  83. package/dist/init-lane-validation.js +147 -0
  84. package/dist/init-lane-validation.js.map +1 -0
  85. package/dist/init-scaffolding.js +158 -0
  86. package/dist/init-scaffolding.js.map +1 -0
  87. package/dist/init-templates.js +1983 -0
  88. package/dist/init-templates.js.map +1 -0
  89. package/dist/init.js.map +1 -0
  90. package/dist/initiative-add-wu.js.map +1 -0
  91. package/dist/initiative-bulk-assign-wus.js.map +1 -0
  92. package/dist/initiative-create.js.map +1 -0
  93. package/dist/initiative-edit.js.map +1 -0
  94. package/dist/initiative-list.js.map +1 -0
  95. package/dist/initiative-plan.js.map +1 -0
  96. package/dist/initiative-remove-wu.js.map +1 -0
  97. package/dist/initiative-status.js.map +1 -0
  98. package/dist/lane-edit.js.map +1 -0
  99. package/dist/lane-health.js.map +1 -0
  100. package/dist/lane-lifecycle-process.js +381 -0
  101. package/dist/lane-lifecycle-process.js.map +1 -0
  102. package/dist/lane-lock.js.map +1 -0
  103. package/dist/lane-setup.js.map +1 -0
  104. package/dist/lane-status.js.map +1 -0
  105. package/dist/lane-suggest.js.map +1 -0
  106. package/dist/lane-validate.js.map +1 -0
  107. package/dist/lifecycle-regression-harness.js +181 -0
  108. package/dist/lifecycle-regression-harness.js.map +1 -0
  109. package/dist/lumenflow-upgrade.js +18 -10
  110. package/dist/lumenflow-upgrade.js.map +1 -0
  111. package/dist/mem-checkpoint.js.map +1 -0
  112. package/dist/mem-cleanup.js.map +1 -0
  113. package/dist/mem-context.js.map +1 -0
  114. package/dist/mem-create.js.map +1 -0
  115. package/dist/mem-delete.js.map +1 -0
  116. package/dist/mem-export.js.map +1 -0
  117. package/dist/mem-inbox.js.map +1 -0
  118. package/dist/mem-index.js +214 -0
  119. package/dist/mem-index.js.map +1 -0
  120. package/dist/mem-init.js.map +1 -0
  121. package/dist/mem-profile.js +210 -0
  122. package/dist/mem-profile.js.map +1 -0
  123. package/dist/mem-promote.js +257 -0
  124. package/dist/mem-promote.js.map +1 -0
  125. package/dist/mem-ready.js.map +1 -0
  126. package/dist/mem-recover.js.map +1 -0
  127. package/dist/mem-signal.js.map +1 -0
  128. package/dist/mem-start.js.map +1 -0
  129. package/dist/mem-summarize.js.map +1 -0
  130. package/dist/mem-triage.js.map +1 -0
  131. package/dist/merge-block.js +225 -0
  132. package/dist/merge-block.js.map +1 -0
  133. package/dist/metrics-cli.js.map +1 -0
  134. package/dist/metrics-snapshot.js.map +1 -0
  135. package/dist/object-guards.js +9 -0
  136. package/dist/object-guards.js.map +1 -0
  137. package/dist/onboard.js.map +1 -0
  138. package/dist/onboarding-smoke-test.js +432 -0
  139. package/dist/onboarding-smoke-test.js.map +1 -0
  140. package/dist/orchestrate-init-status.js.map +1 -0
  141. package/dist/orchestrate-initiative.js.map +1 -0
  142. package/dist/orchestrate-monitor.js.map +1 -0
  143. package/dist/pack-author.js.map +1 -0
  144. package/dist/pack-hash.js.map +1 -0
  145. package/dist/pack-install.js.map +1 -0
  146. package/dist/pack-publish.js.map +1 -0
  147. package/dist/pack-scaffold.js.map +1 -0
  148. package/dist/pack-search.js.map +1 -0
  149. package/dist/pack-validate.js.map +1 -0
  150. package/dist/plan-create.js.map +1 -0
  151. package/dist/plan-edit.js.map +1 -0
  152. package/dist/plan-link.js.map +1 -0
  153. package/dist/plan-promote.js.map +1 -0
  154. package/dist/public-manifest.js +931 -0
  155. package/dist/public-manifest.js.map +1 -0
  156. package/dist/release.js +664 -116
  157. package/dist/release.js.map +1 -0
  158. package/dist/rotate-progress.js +253 -0
  159. package/dist/rotate-progress.js.map +1 -0
  160. package/dist/session-coordinator.js +303 -0
  161. package/dist/session-coordinator.js.map +1 -0
  162. package/dist/shared-validators.js +81 -0
  163. package/dist/shared-validators.js.map +1 -0
  164. package/dist/signal-cleanup.js.map +1 -0
  165. package/dist/state-bootstrap.js.map +1 -0
  166. package/dist/state-cleanup.js.map +1 -0
  167. package/dist/state-doctor-fix.js +226 -0
  168. package/dist/state-doctor-fix.js.map +1 -0
  169. package/dist/state-doctor-stamps.js +23 -0
  170. package/dist/state-doctor-stamps.js.map +1 -0
  171. package/dist/state-doctor.js.map +1 -0
  172. package/dist/strict-progress.js +255 -0
  173. package/dist/strict-progress.js.map +1 -0
  174. package/dist/sync-templates.js.map +1 -0
  175. package/dist/task-claim.js.map +1 -0
  176. package/dist/trace-gen.js +401 -0
  177. package/dist/trace-gen.js.map +1 -0
  178. package/dist/validate-agent-skills.js +224 -0
  179. package/dist/validate-agent-skills.js.map +1 -0
  180. package/dist/validate-agent-sync.js +152 -0
  181. package/dist/validate-agent-sync.js.map +1 -0
  182. package/dist/validate-backlog-sync.js +77 -0
  183. package/dist/validate-backlog-sync.js.map +1 -0
  184. package/dist/validate-skills-spec.js +211 -0
  185. package/dist/validate-skills-spec.js.map +1 -0
  186. package/dist/validate.js.map +1 -0
  187. package/dist/validator-defaults.js +107 -0
  188. package/dist/validator-defaults.js.map +1 -0
  189. package/dist/validator-registry.js +71 -0
  190. package/dist/validator-registry.js.map +1 -0
  191. package/dist/workspace-init.js.map +1 -0
  192. package/dist/wu-block.js.map +1 -0
  193. package/dist/wu-brief.js.map +1 -0
  194. package/dist/wu-claim-branch.js +123 -0
  195. package/dist/wu-claim-branch.js.map +1 -0
  196. package/dist/wu-claim-cloud.js +79 -0
  197. package/dist/wu-claim-cloud.js.map +1 -0
  198. package/dist/wu-claim-mode.js +82 -0
  199. package/dist/wu-claim-mode.js.map +1 -0
  200. package/dist/wu-claim-output.js +85 -0
  201. package/dist/wu-claim-output.js.map +1 -0
  202. package/dist/wu-claim-repair-guidance.js +12 -0
  203. package/dist/wu-claim-repair-guidance.js.map +1 -0
  204. package/dist/wu-claim-resume-handler.js +87 -0
  205. package/dist/wu-claim-resume-handler.js.map +1 -0
  206. package/dist/wu-claim-state.js +581 -0
  207. package/dist/wu-claim-state.js.map +1 -0
  208. package/dist/wu-claim-validation.js +458 -0
  209. package/dist/wu-claim-validation.js.map +1 -0
  210. package/dist/wu-claim-worktree.js +238 -0
  211. package/dist/wu-claim-worktree.js.map +1 -0
  212. package/dist/wu-claim.js.map +1 -0
  213. package/dist/wu-cleanup-cloud.js +78 -0
  214. package/dist/wu-cleanup-cloud.js.map +1 -0
  215. package/dist/wu-cleanup.js.map +1 -0
  216. package/dist/wu-code-path-coverage.js +83 -0
  217. package/dist/wu-code-path-coverage.js.map +1 -0
  218. package/dist/wu-create-cloud.js +30 -0
  219. package/dist/wu-create-cloud.js.map +1 -0
  220. package/dist/wu-create-content.js +264 -0
  221. package/dist/wu-create-content.js.map +1 -0
  222. package/dist/wu-create-readiness.js +59 -0
  223. package/dist/wu-create-readiness.js.map +1 -0
  224. package/dist/wu-create-validation.js +128 -0
  225. package/dist/wu-create-validation.js.map +1 -0
  226. package/dist/wu-create.js.map +1 -0
  227. package/dist/wu-delegate.js.map +1 -0
  228. package/dist/wu-delete.js.map +1 -0
  229. package/dist/wu-deps.js.map +1 -0
  230. package/dist/wu-done-auto-cleanup.js +194 -0
  231. package/dist/wu-done-auto-cleanup.js.map +1 -0
  232. package/dist/wu-done-check.js +38 -0
  233. package/dist/wu-done-check.js.map +1 -0
  234. package/dist/wu-done-cloud.js +48 -0
  235. package/dist/wu-done-cloud.js.map +1 -0
  236. package/dist/wu-done-decay.js +83 -0
  237. package/dist/wu-done-decay.js.map +1 -0
  238. package/dist/wu-done.js.map +1 -0
  239. package/dist/wu-edit-operations.js +399 -0
  240. package/dist/wu-edit-operations.js.map +1 -0
  241. package/dist/wu-edit-validators.js +282 -0
  242. package/dist/wu-edit-validators.js.map +1 -0
  243. package/dist/wu-edit.js.map +1 -0
  244. package/dist/wu-infer-lane.js.map +1 -0
  245. package/dist/wu-preflight.js.map +1 -0
  246. package/dist/wu-prep.js.map +1 -0
  247. package/dist/wu-proto.js.map +1 -0
  248. package/dist/wu-prune.js.map +1 -0
  249. package/dist/wu-recover.js.map +1 -0
  250. package/dist/wu-release.js.map +1 -0
  251. package/dist/wu-repair.js.map +1 -0
  252. package/dist/wu-sandbox.js.map +1 -0
  253. package/dist/wu-spawn-completion.js +58 -0
  254. package/dist/wu-spawn-completion.js.map +1 -0
  255. package/dist/wu-spawn-prompt-builders.js +1190 -0
  256. package/dist/wu-spawn-prompt-builders.js.map +1 -0
  257. package/dist/wu-spawn-strategy-resolver.js +322 -0
  258. package/dist/wu-spawn-strategy-resolver.js.map +1 -0
  259. package/dist/wu-spawn.js +59 -0
  260. package/dist/wu-spawn.js.map +1 -0
  261. package/dist/wu-state-cloud.js +41 -0
  262. package/dist/wu-state-cloud.js.map +1 -0
  263. package/dist/wu-status.js.map +1 -0
  264. package/dist/wu-unblock.js.map +1 -0
  265. package/dist/wu-unlock-lane.js.map +1 -0
  266. package/dist/wu-validate.js.map +1 -0
  267. package/package.json +8 -10
@@ -0,0 +1,380 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * @file enforcement-sync.ts
5
+ * Sync enforcement hooks based on LumenFlow configuration (WU-1367)
6
+ *
7
+ * This module handles syncing Claude Code hooks during setup when
8
+ * enforcement.hooks=true in the configuration.
9
+ */
10
+ // fs operations use runtime-provided paths from LumenFlow configuration
11
+ // Object injection sink warnings are false positives for array indexing
12
+ import * as fs from 'node:fs';
13
+ import * as path from 'node:path';
14
+ import { getConfig } from '@lumenflow/core/config';
15
+ import { generateEnforcementHooks, generateEnforceWorktreeScript, generateRequireWuScript, generateWarnIncompleteScript, generatePreCompactCheckpointScript, generateSessionStartRecoveryScript, generateAutoCheckpointScript, HOOK_SCRIPTS, } from './enforcement-generator.js';
16
+ import { checkAutoCheckpointWarning } from './auto-checkpoint-utils.js';
17
+ /**
18
+ * Read LumenFlow configuration from workspace.yaml software_delivery.
19
+ *
20
+ * @param projectDir - Project directory
21
+ * @returns Parsed configuration or null if not found
22
+ */
23
+ function readLumenFlowConfig(projectDir) {
24
+ try {
25
+ return getConfig({ projectRoot: projectDir, reload: true });
26
+ }
27
+ catch {
28
+ return null;
29
+ }
30
+ }
31
+ /**
32
+ * Get enforcement configuration from LumenFlow config
33
+ *
34
+ * @param config - LumenFlow configuration
35
+ * @returns Enforcement config or null if not enabled
36
+ */
37
+ function getEnforcementConfig(config) {
38
+ // WU-1681: Find enforcement config from UnsafeAny configured client (not just claude-code)
39
+ const clients = config?.agents?.clients;
40
+ const enforcement = clients
41
+ ? Object.values(clients).find((c) => c?.enforcement?.hooks)?.enforcement
42
+ : undefined;
43
+ if (!enforcement || !enforcement.hooks) {
44
+ return null;
45
+ }
46
+ // WU-1471: Extract auto-checkpoint config from memory.enforcement
47
+ const memoryEnforcement = config?.memory?.enforcement;
48
+ const autoCheckpoint = memoryEnforcement?.auto_checkpoint;
49
+ return {
50
+ hooks: enforcement.hooks ?? false,
51
+ block_outside_worktree: enforcement.block_outside_worktree ?? false,
52
+ require_wu_for_edits: enforcement.require_wu_for_edits ?? false,
53
+ warn_on_stop_without_wu_done: enforcement.warn_on_stop_without_wu_done ?? false,
54
+ auto_checkpoint: autoCheckpoint?.enabled
55
+ ? {
56
+ enabled: true,
57
+ interval_tool_calls: autoCheckpoint.interval_tool_calls ?? 30,
58
+ }
59
+ : undefined,
60
+ };
61
+ }
62
+ /**
63
+ * Read existing Claude settings.json
64
+ *
65
+ * @param projectDir - Project directory
66
+ * @returns Parsed settings or default structure
67
+ */
68
+ function readClaudeSettings(projectDir) {
69
+ const settingsPath = path.join(projectDir, '.claude', 'settings.json');
70
+ if (!fs.existsSync(settingsPath)) {
71
+ return {
72
+ $schema: 'https://json.schemastore.org/claude-code-settings.json',
73
+ permissions: {
74
+ allow: ['Bash', 'Read', 'Write', 'Edit'],
75
+ },
76
+ };
77
+ }
78
+ try {
79
+ const content = fs.readFileSync(settingsPath, 'utf-8');
80
+ return JSON.parse(content);
81
+ }
82
+ catch {
83
+ return {
84
+ $schema: 'https://json.schemastore.org/claude-code-settings.json',
85
+ };
86
+ }
87
+ }
88
+ /**
89
+ * Write Claude settings.json
90
+ *
91
+ * @param projectDir - Project directory
92
+ * @param settings - Settings to write
93
+ */
94
+ function writeClaudeSettings(projectDir, settings) {
95
+ const claudeDir = path.join(projectDir, '.claude');
96
+ const settingsPath = path.join(claudeDir, 'settings.json');
97
+ if (!fs.existsSync(claudeDir)) {
98
+ fs.mkdirSync(claudeDir, { recursive: true });
99
+ }
100
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
101
+ }
102
+ /**
103
+ * Write hook script to .claude/hooks/
104
+ *
105
+ * @param projectDir - Project directory
106
+ * @param filename - Script filename
107
+ * @param content - Script content
108
+ */
109
+ function writeHookScript(projectDir, filename, content) {
110
+ const hooksDir = path.join(projectDir, '.claude', 'hooks');
111
+ if (!fs.existsSync(hooksDir)) {
112
+ fs.mkdirSync(hooksDir, { recursive: true });
113
+ }
114
+ const scriptPath = path.join(hooksDir, filename);
115
+ fs.writeFileSync(scriptPath, content, { mode: 0o755 });
116
+ }
117
+ /**
118
+ * Merge generated hooks with existing hooks in settings
119
+ *
120
+ * @param existing - Existing settings
121
+ * @param generated - Generated hooks
122
+ * @returns Merged settings
123
+ */
124
+ // Complexity is acceptable for hook merging logic - alternative would over-abstract
125
+ // eslint-disable-next-line sonarjs/cognitive-complexity
126
+ function mergeHooksIntoSettings(existing, generated) {
127
+ const result = { ...existing };
128
+ if (!result.hooks) {
129
+ result.hooks = {};
130
+ }
131
+ // Merge PreToolUse hooks
132
+ if (generated.preToolUse) {
133
+ if (!result.hooks.PreToolUse) {
134
+ result.hooks.PreToolUse = [];
135
+ }
136
+ for (const newHook of generated.preToolUse) {
137
+ // Find existing entry with same matcher
138
+ const existingIndex = result.hooks.PreToolUse.findIndex((h) => h.matcher === newHook.matcher);
139
+ if (existingIndex >= 0) {
140
+ // Merge hooks into existing entry, avoiding duplicates
141
+ const existing = result.hooks.PreToolUse[existingIndex];
142
+ for (const hook of newHook.hooks) {
143
+ const isDuplicate = existing.hooks.some((h) => h.command === hook.command);
144
+ if (!isDuplicate) {
145
+ existing.hooks.push(hook);
146
+ }
147
+ }
148
+ }
149
+ else {
150
+ result.hooks.PreToolUse.push(newHook);
151
+ }
152
+ }
153
+ }
154
+ // Merge Stop hooks
155
+ if (generated.stop) {
156
+ if (!result.hooks.Stop) {
157
+ result.hooks.Stop = [];
158
+ }
159
+ for (const newHook of generated.stop) {
160
+ const existingIndex = result.hooks.Stop.findIndex((h) => h.matcher === newHook.matcher);
161
+ if (existingIndex >= 0) {
162
+ const existing = result.hooks.Stop[existingIndex];
163
+ for (const hook of newHook.hooks) {
164
+ const isDuplicate = existing.hooks.some((h) => h.command === hook.command);
165
+ if (!isDuplicate) {
166
+ existing.hooks.push(hook);
167
+ }
168
+ }
169
+ }
170
+ else {
171
+ result.hooks.Stop.push(newHook);
172
+ }
173
+ }
174
+ }
175
+ // Merge PreCompact hooks (WU-1394)
176
+ if (generated.preCompact) {
177
+ if (!result.hooks.PreCompact) {
178
+ result.hooks.PreCompact = [];
179
+ }
180
+ for (const newHook of generated.preCompact) {
181
+ const existingIndex = result.hooks.PreCompact.findIndex((h) => h.matcher === newHook.matcher);
182
+ if (existingIndex >= 0) {
183
+ const existing = result.hooks.PreCompact[existingIndex];
184
+ for (const hook of newHook.hooks) {
185
+ const isDuplicate = existing.hooks.some((h) => h.command === hook.command);
186
+ if (!isDuplicate) {
187
+ existing.hooks.push(hook);
188
+ }
189
+ }
190
+ }
191
+ else {
192
+ result.hooks.PreCompact.push(newHook);
193
+ }
194
+ }
195
+ }
196
+ // Merge SessionStart hooks (WU-1394)
197
+ if (generated.sessionStart) {
198
+ if (!result.hooks.SessionStart) {
199
+ result.hooks.SessionStart = [];
200
+ }
201
+ for (const newHook of generated.sessionStart) {
202
+ const existingIndex = result.hooks.SessionStart.findIndex((h) => h.matcher === newHook.matcher);
203
+ if (existingIndex >= 0) {
204
+ const existing = result.hooks.SessionStart[existingIndex];
205
+ for (const hook of newHook.hooks) {
206
+ const isDuplicate = existing.hooks.some((h) => h.command === hook.command);
207
+ if (!isDuplicate) {
208
+ existing.hooks.push(hook);
209
+ }
210
+ }
211
+ }
212
+ else {
213
+ result.hooks.SessionStart.push(newHook);
214
+ }
215
+ }
216
+ }
217
+ // WU-1471: Merge PostToolUse hooks (auto-checkpoint)
218
+ if (generated.postToolUse) {
219
+ if (!result.hooks.PostToolUse) {
220
+ result.hooks.PostToolUse = [];
221
+ }
222
+ for (const newHook of generated.postToolUse) {
223
+ const existingIndex = result.hooks.PostToolUse.findIndex((h) => h.matcher === newHook.matcher);
224
+ if (existingIndex >= 0) {
225
+ const existing = result.hooks.PostToolUse[existingIndex];
226
+ for (const hook of newHook.hooks) {
227
+ const isDuplicate = existing.hooks.some((h) => h.command === hook.command);
228
+ if (!isDuplicate) {
229
+ existing.hooks.push(hook);
230
+ }
231
+ }
232
+ }
233
+ else {
234
+ result.hooks.PostToolUse.push(newHook);
235
+ }
236
+ }
237
+ }
238
+ // WU-1471: Merge SubagentStop hooks (auto-checkpoint on sub-agent finish)
239
+ if (generated.subagentStop) {
240
+ if (!result.hooks.SubagentStop) {
241
+ result.hooks.SubagentStop = [];
242
+ }
243
+ for (const newHook of generated.subagentStop) {
244
+ const existingIndex = result.hooks.SubagentStop.findIndex((h) => h.matcher === newHook.matcher);
245
+ if (existingIndex >= 0) {
246
+ const existing = result.hooks.SubagentStop[existingIndex];
247
+ for (const hook of newHook.hooks) {
248
+ const isDuplicate = existing.hooks.some((h) => h.command === hook.command);
249
+ if (!isDuplicate) {
250
+ existing.hooks.push(hook);
251
+ }
252
+ }
253
+ }
254
+ else {
255
+ result.hooks.SubagentStop.push(newHook);
256
+ }
257
+ }
258
+ }
259
+ return result;
260
+ }
261
+ /**
262
+ * Sync enforcement hooks based on LumenFlow configuration.
263
+ *
264
+ * This function:
265
+ * 1. Reads workspace.yaml software_delivery
266
+ * 2. Checks if enforcement.hooks=true for claude-code
267
+ * 3. Generates and writes hook scripts
268
+ * 4. Updates .claude/settings.json with hook configuration
269
+ *
270
+ * @param projectDir - Project directory
271
+ * @returns True if hooks were synced, false if skipped
272
+ */
273
+ export async function syncEnforcementHooks(projectDir) {
274
+ // Read LumenFlow config
275
+ const config = readLumenFlowConfig(projectDir);
276
+ const enforcement = getEnforcementConfig(config);
277
+ // Skip if enforcement not enabled
278
+ if (!enforcement || !enforcement.hooks) {
279
+ return false;
280
+ }
281
+ // WU-1471: Check for auto-checkpoint mismatch warning (AC5)
282
+ // Also check memory config independently for the case where hooks=true but
283
+ // auto_checkpoint config comes from memory.enforcement section
284
+ const memoryEnforcement = config?.memory?.enforcement;
285
+ const autoCheckpointEnabled = memoryEnforcement?.auto_checkpoint?.enabled ?? false;
286
+ const warningResult = checkAutoCheckpointWarning({
287
+ hooksEnabled: enforcement.hooks,
288
+ autoCheckpointEnabled,
289
+ });
290
+ if (warningResult.warning && warningResult.message) {
291
+ console.warn(`[enforcement-sync] ${warningResult.message}`);
292
+ }
293
+ // Generate hooks based on config
294
+ const generatedHooks = generateEnforcementHooks({
295
+ block_outside_worktree: enforcement.block_outside_worktree,
296
+ require_wu_for_edits: enforcement.require_wu_for_edits,
297
+ warn_on_stop_without_wu_done: enforcement.warn_on_stop_without_wu_done,
298
+ auto_checkpoint: enforcement.auto_checkpoint,
299
+ });
300
+ // Write hook scripts
301
+ if (enforcement.block_outside_worktree) {
302
+ writeHookScript(projectDir, HOOK_SCRIPTS.ENFORCE_WORKTREE, generateEnforceWorktreeScript());
303
+ }
304
+ if (enforcement.require_wu_for_edits) {
305
+ writeHookScript(projectDir, HOOK_SCRIPTS.REQUIRE_WU, generateRequireWuScript());
306
+ }
307
+ if (enforcement.warn_on_stop_without_wu_done) {
308
+ writeHookScript(projectDir, HOOK_SCRIPTS.WARN_INCOMPLETE, generateWarnIncompleteScript());
309
+ }
310
+ // WU-1471: Write auto-checkpoint hook script when enabled
311
+ if (enforcement.auto_checkpoint?.enabled) {
312
+ writeHookScript(projectDir, HOOK_SCRIPTS.AUTO_CHECKPOINT, generateAutoCheckpointScript(enforcement.auto_checkpoint.interval_tool_calls));
313
+ }
314
+ // Always write recovery hook scripts when enforcement.hooks is enabled (WU-1394)
315
+ // These enable durable context recovery after compaction
316
+ writeHookScript(projectDir, HOOK_SCRIPTS.PRE_COMPACT_CHECKPOINT, generatePreCompactCheckpointScript());
317
+ writeHookScript(projectDir, HOOK_SCRIPTS.SESSION_START_RECOVERY, generateSessionStartRecoveryScript());
318
+ // Update settings.json
319
+ const existingSettings = readClaudeSettings(projectDir);
320
+ const updatedSettings = mergeHooksIntoSettings(existingSettings, generatedHooks);
321
+ writeClaudeSettings(projectDir, updatedSettings);
322
+ return true;
323
+ }
324
+ /**
325
+ * Remove enforcement hooks from settings.json
326
+ *
327
+ * @param projectDir - Project directory
328
+ */
329
+ export async function removeEnforcementHooks(projectDir) {
330
+ const settings = readClaudeSettings(projectDir);
331
+ if (!settings.hooks) {
332
+ return;
333
+ }
334
+ // Remove enforcement-related hooks (includes all LumenFlow hook scripts)
335
+ const enforcementCommands = Object.values(HOOK_SCRIPTS);
336
+ if (settings.hooks.PreToolUse) {
337
+ settings.hooks.PreToolUse = settings.hooks.PreToolUse.map((entry) => ({
338
+ ...entry,
339
+ hooks: entry.hooks.filter((h) => !enforcementCommands.some((cmd) => h.command.includes(cmd))),
340
+ })).filter((entry) => entry.hooks.length > 0);
341
+ if (settings.hooks.PreToolUse.length === 0) {
342
+ delete settings.hooks.PreToolUse;
343
+ }
344
+ }
345
+ if (settings.hooks.Stop) {
346
+ settings.hooks.Stop = settings.hooks.Stop.map((entry) => ({
347
+ ...entry,
348
+ hooks: entry.hooks.filter((h) => !enforcementCommands.some((cmd) => h.command.includes(cmd))),
349
+ })).filter((entry) => entry.hooks.length > 0);
350
+ if (settings.hooks.Stop.length === 0) {
351
+ delete settings.hooks.Stop;
352
+ }
353
+ }
354
+ // WU-1471: Remove PostToolUse hooks
355
+ if (settings.hooks.PostToolUse) {
356
+ settings.hooks.PostToolUse = settings.hooks.PostToolUse.map((entry) => ({
357
+ ...entry,
358
+ hooks: entry.hooks.filter((h) => !enforcementCommands.some((cmd) => h.command.includes(cmd))),
359
+ })).filter((entry) => entry.hooks.length > 0);
360
+ if (settings.hooks.PostToolUse.length === 0) {
361
+ delete settings.hooks.PostToolUse;
362
+ }
363
+ }
364
+ // WU-1471: Remove SubagentStop hooks
365
+ if (settings.hooks.SubagentStop) {
366
+ settings.hooks.SubagentStop = settings.hooks.SubagentStop.map((entry) => ({
367
+ ...entry,
368
+ hooks: entry.hooks.filter((h) => !enforcementCommands.some((cmd) => h.command.includes(cmd))),
369
+ })).filter((entry) => entry.hooks.length > 0);
370
+ if (settings.hooks.SubagentStop.length === 0) {
371
+ delete settings.hooks.SubagentStop;
372
+ }
373
+ }
374
+ // Clean up empty hooks object
375
+ if (Object.keys(settings.hooks).length === 0) {
376
+ delete settings.hooks;
377
+ }
378
+ writeClaudeSettings(projectDir, settings);
379
+ }
380
+ //# sourceMappingURL=enforcement-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enforcement-sync.js","sourceRoot":"","sources":["../../src/hooks/enforcement-sync.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * @file generators/auto-checkpoint.ts
5
+ * Generate the auto-checkpoint.sh hook script content (WU-1471).
6
+ *
7
+ * Extracted from enforcement-generator.ts by WU-1645.
8
+ */
9
+ /**
10
+ * WU-1471: Generate the auto-checkpoint.sh hook script content.
11
+ *
12
+ * This hook is used by both PostToolUse and SubagentStop events.
13
+ * It branches on the hook_event_name environment variable:
14
+ * - PostToolUse: Increments a per-WU counter and checkpoints at interval
15
+ * - SubagentStop: Always creates a checkpoint (sub-agent finished work)
16
+ *
17
+ * Uses a defensive subshell to background checkpoint writes so the hook
18
+ * returns quickly and does not block the agent.
19
+ *
20
+ * @param intervalToolCalls - Number of tool calls between auto-checkpoints
21
+ * @returns Shell script content
22
+ */
23
+ export function generateAutoCheckpointScript(intervalToolCalls) {
24
+ // Note: Shell variable escapes (\$, \") are intentional for the generated bash script
25
+ /* eslint-disable no-useless-escape */
26
+ return `#!/bin/bash
27
+ #
28
+ # auto-checkpoint.sh (WU-1471)
29
+ #
30
+ # PostToolUse + SubagentStop hook for automatic checkpointing.
31
+ # Branches on hook_event_name to decide behavior:
32
+ # - PostToolUse: counter-based checkpoint at interval
33
+ # - SubagentStop: always checkpoint (sub-agent completed work)
34
+ #
35
+ # Checkpoint writes are backgrounded in a defensive subshell
36
+ # to avoid blocking the agent.
37
+ #
38
+ # Exit codes:
39
+ # 0 = Always (never blocks tool execution)
40
+ #
41
+
42
+ # Fail-open: UnsafeAny error allows the operation to continue
43
+ set +e
44
+
45
+ INTERVAL=${intervalToolCalls}
46
+
47
+ # Derive repo paths
48
+ if [[ -z "\\\${CLAUDE_PROJECT_DIR:-}" ]]; then
49
+ exit 0
50
+ fi
51
+
52
+ REPO_PATH="\\\$CLAUDE_PROJECT_DIR"
53
+ LUMENFLOW_DIR="\\\${REPO_PATH}/.lumenflow"
54
+ COUNTERS_DIR="\\\${LUMENFLOW_DIR}/state/hook-counters"
55
+
56
+ # Check if LumenFlow is configured
57
+ if [[ ! -d "\\\$LUMENFLOW_DIR" ]]; then
58
+ exit 0
59
+ fi
60
+
61
+ # Detect WU ID from worktree context
62
+ WU_ID=""
63
+ CWD=\\\$(pwd 2>/dev/null || echo "")
64
+ if [[ "\\\$CWD" == *"/worktrees/"* ]]; then
65
+ # Extract WU ID from worktree path (e.g., worktrees/framework-cli-wu-1471)
66
+ WORKTREE_NAME=\\\$(basename "\\\$CWD")
67
+ WU_ID=\\\$(echo "\\\$WORKTREE_NAME" | grep -oiE 'wu-[0-9]+' | head -1 | tr '[:lower:]' '[:upper:]')
68
+ fi
69
+
70
+ if [[ -z "\\\$WU_ID" ]]; then
71
+ exit 0
72
+ fi
73
+
74
+ # Determine hook event name (set by Claude Code runtime)
75
+ HOOK_EVENT="\\\${hook_event_name:-PostToolUse}"
76
+
77
+ # Branch on event type
78
+ case "\\\$HOOK_EVENT" in
79
+ SubagentStop)
80
+ # Always checkpoint when sub-agent stops
81
+ (
82
+ pnpm mem:checkpoint "Auto: sub-agent completed" --wu "\\\$WU_ID" --trigger "subagent-stop" --quiet 2>/dev/null || true
83
+ ) &
84
+ ;;
85
+ *)
86
+ # PostToolUse (default): counter-based checkpointing
87
+ mkdir -p "\\\$COUNTERS_DIR" 2>/dev/null || true
88
+ COUNTER_FILE="\\\${COUNTERS_DIR}/\\\${WU_ID}.json"
89
+
90
+ # Read current count (default 0)
91
+ COUNT=0
92
+ if [[ -f "\\\$COUNTER_FILE" ]]; then
93
+ COUNT=\\\$(python3 -c "
94
+ import json
95
+ try:
96
+ with open('\\\$COUNTER_FILE', 'r') as f:
97
+ data = json.load(f)
98
+ print(data.get('count', 0))
99
+ except:
100
+ print(0)
101
+ " 2>/dev/null || echo "0")
102
+ fi
103
+
104
+ # Increment counter
105
+ COUNT=\\\$((COUNT + 1))
106
+
107
+ # Check if we've reached the interval
108
+ if [[ \\\$COUNT -ge \\\$INTERVAL ]]; then
109
+ # Reset counter and checkpoint in background
110
+ echo '{"count": 0}' > "\\\$COUNTER_FILE" 2>/dev/null || true
111
+ (
112
+ pnpm mem:checkpoint "Auto: \\\${COUNT} tool calls" --wu "\\\$WU_ID" --trigger "auto-interval" --quiet 2>/dev/null || true
113
+ ) &
114
+ else
115
+ # Just update the counter
116
+ echo "{\\\\\\"count\\\\\\": \\\$COUNT}" > "\\\$COUNTER_FILE" 2>/dev/null || true
117
+ fi
118
+ ;;
119
+ esac
120
+
121
+ exit 0
122
+ `;
123
+ /* eslint-enable no-useless-escape */
124
+ }
125
+ //# sourceMappingURL=auto-checkpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-checkpoint.js","sourceRoot":"","sources":["../../../src/hooks/generators/auto-checkpoint.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yCAAyC;AAEzC;;;;;GAKG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,4BAA4B,CAAC,iBAAyB;IACpE,sFAAsF;IACtF,sCAAsC;IACtC,OAAO;;;;;;;;;;;;;;;;;;;WAmBE,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6E3B,CAAC;IACA,qCAAqC;AACvC,CAAC"}