@lumenflow/cli 3.18.1 → 3.20.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 (175) hide show
  1. package/dist/docs-sync.js +123 -6
  2. package/dist/docs-sync.js.map +1 -1
  3. package/dist/gate-co-change.js +23 -4
  4. package/dist/gate-co-change.js.map +1 -1
  5. package/dist/gates-runners.js +113 -16
  6. package/dist/gates-runners.js.map +1 -1
  7. package/dist/gates-utils.js +71 -0
  8. package/dist/gates-utils.js.map +1 -1
  9. package/dist/lumenflow-upgrade.js +1 -0
  10. package/dist/lumenflow-upgrade.js.map +1 -1
  11. package/dist/public-manifest.js +1 -1
  12. package/dist/public-manifest.js.map +1 -1
  13. package/dist/sync-templates.js +13 -0
  14. package/dist/sync-templates.js.map +1 -1
  15. package/dist/wu-block.js +10 -0
  16. package/dist/wu-block.js.map +1 -1
  17. package/dist/wu-claim-validation.js +3 -1
  18. package/dist/wu-claim-validation.js.map +1 -1
  19. package/dist/wu-claim.js +3 -1
  20. package/dist/wu-claim.js.map +1 -1
  21. package/dist/wu-done-memory-telemetry.js +5 -1
  22. package/dist/wu-done-memory-telemetry.js.map +1 -1
  23. package/dist/wu-done-ownership.js +6 -0
  24. package/dist/wu-done-ownership.js.map +1 -1
  25. package/dist/wu-edit-operations.js +4 -4
  26. package/dist/wu-edit-operations.js.map +1 -1
  27. package/dist/wu-prep.js +88 -13
  28. package/dist/wu-prep.js.map +1 -1
  29. package/dist/wu-prune.js +2 -2
  30. package/dist/wu-prune.js.map +1 -1
  31. package/dist/wu-recover.js +15 -0
  32. package/dist/wu-recover.js.map +1 -1
  33. package/dist/wu-release.js +10 -1
  34. package/dist/wu-release.js.map +1 -1
  35. package/dist/wu-spawn-prompt-builders.js +27 -2
  36. package/dist/wu-spawn-prompt-builders.js.map +1 -1
  37. package/dist/wu-state-mutation-ownership.js +136 -0
  38. package/dist/wu-state-mutation-ownership.js.map +1 -0
  39. package/dist/wu-unblock.js +10 -0
  40. package/dist/wu-unblock.js.map +1 -1
  41. package/dist/wu-verify.js +22 -17
  42. package/dist/wu-verify.js.map +1 -1
  43. package/package.json +111 -110
  44. package/packs/agent-runtime/.turbo/turbo-build.log +1 -1
  45. package/packs/agent-runtime/package.json +1 -1
  46. package/packs/sidekick/.turbo/turbo-build.log +1 -1
  47. package/packs/sidekick/README.md +118 -113
  48. package/packs/sidekick/manifest-schema.ts +15 -228
  49. package/packs/sidekick/manifest.ts +107 -7
  50. package/packs/sidekick/manifest.yaml +199 -1
  51. package/packs/sidekick/package.json +4 -1
  52. package/packs/sidekick/policy-factory.ts +38 -0
  53. package/packs/sidekick/tool-impl/channel-tools.ts +99 -0
  54. package/packs/sidekick/tool-impl/memory-tools.ts +86 -1
  55. package/packs/sidekick/tool-impl/routine-tools.ts +156 -2
  56. package/packs/sidekick/tool-impl/storage.ts +6 -5
  57. package/packs/sidekick/tool-impl/task-tools.ts +186 -4
  58. package/packs/software-delivery/.turbo/turbo-build.log +1 -1
  59. package/packs/software-delivery/package.json +1 -1
  60. package/templates/core/AGENTS.md.template +157 -32
  61. package/templates/core/LUMENFLOW.md.template +44 -29
  62. package/templates/core/_frameworks/lumenflow/wu-sizing-guide.md.template +644 -0
  63. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +5 -5
  64. package/templates/core/ai/onboarding/agent-safety-card.md.template +1 -0
  65. package/templates/core/ai/onboarding/docs-generation.md.template +94 -4
  66. package/templates/core/ai/onboarding/first-15-mins.md.template +1 -1
  67. package/templates/core/ai/onboarding/first-wu-mistakes.md.template +2 -1
  68. package/templates/core/ai/onboarding/initiative-orchestration.md.template +21 -21
  69. package/templates/core/ai/onboarding/quick-ref-commands.md.template +126 -109
  70. package/templates/core/ai/onboarding/release-process.md.template +12 -12
  71. package/templates/core/ai/onboarding/starting-prompt.md.template +33 -32
  72. package/templates/vendors/claude/.claude/skills/initiative-management/SKILL.md.template +2 -2
  73. package/templates/vendors/claude/.claude/skills/multi-agent-coordination/SKILL.md.template +2 -2
  74. package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +3 -3
  75. package/dist/chunk-2D2VOCA4.js +0 -37
  76. package/dist/chunk-2D5KFYGX.js +0 -284
  77. package/dist/chunk-2GXVIN57.js +0 -14072
  78. package/dist/chunk-2MQ7HZWZ.js +0 -26
  79. package/dist/chunk-2UFQ3A3C.js +0 -643
  80. package/dist/chunk-3RG5ZIWI.js +0 -10
  81. package/dist/chunk-4N74J3UT.js +0 -15
  82. package/dist/chunk-5GTOXFYR.js +0 -392
  83. package/dist/chunk-5VY6MQMC.js +0 -240
  84. package/dist/chunk-67XVPMRY.js +0 -1297
  85. package/dist/chunk-6HO4GWJE.js +0 -164
  86. package/dist/chunk-6W5XHWYV.js +0 -1890
  87. package/dist/chunk-6X4EMYJQ.js +0 -64
  88. package/dist/chunk-6XYXI2NQ.js +0 -772
  89. package/dist/chunk-7ANSOV6Q.js +0 -285
  90. package/dist/chunk-A624LFLB.js +0 -1380
  91. package/dist/chunk-ADN5NHG4.js +0 -126
  92. package/dist/chunk-B7YJYJKG.js +0 -33
  93. package/dist/chunk-CCLHCPKG.js +0 -210
  94. package/dist/chunk-CK36VROC.js +0 -1584
  95. package/dist/chunk-D3UOFRSB.js +0 -81
  96. package/dist/chunk-DFR4DJBM.js +0 -230
  97. package/dist/chunk-DSYBDHYH.js +0 -79
  98. package/dist/chunk-DWMLTXKQ.js +0 -1176
  99. package/dist/chunk-E3REJTAJ.js +0 -28
  100. package/dist/chunk-EA3IVO64.js +0 -633
  101. package/dist/chunk-EK2AKZKD.js +0 -55
  102. package/dist/chunk-ELD7JTTT.js +0 -343
  103. package/dist/chunk-EX6TT2XI.js +0 -195
  104. package/dist/chunk-EXINSFZE.js +0 -82
  105. package/dist/chunk-EZ6ZBYBM.js +0 -510
  106. package/dist/chunk-FBKAPTJ2.js +0 -16
  107. package/dist/chunk-FVLV5RYH.js +0 -1118
  108. package/dist/chunk-GDNSBQVK.js +0 -2485
  109. package/dist/chunk-GPQHMBNN.js +0 -278
  110. package/dist/chunk-GTFJB67L.js +0 -68
  111. package/dist/chunk-HANJXVKW.js +0 -1127
  112. package/dist/chunk-HEVS5YLD.js +0 -269
  113. package/dist/chunk-HMEVZKPQ.js +0 -9
  114. package/dist/chunk-HRGSYNLM.js +0 -3511
  115. package/dist/chunk-ISZR5N4K.js +0 -60
  116. package/dist/chunk-J6SUPR2C.js +0 -226
  117. package/dist/chunk-JERYVEIZ.js +0 -244
  118. package/dist/chunk-JHHWGL2N.js +0 -87
  119. package/dist/chunk-JONWQUB5.js +0 -775
  120. package/dist/chunk-K2DIWWDM.js +0 -1766
  121. package/dist/chunk-KY4PGL5V.js +0 -969
  122. package/dist/chunk-L737LQ4C.js +0 -1285
  123. package/dist/chunk-LFTWYIB2.js +0 -497
  124. package/dist/chunk-LV47RFNJ.js +0 -41
  125. package/dist/chunk-MKSAITI7.js +0 -15
  126. package/dist/chunk-MZ7RKIX4.js +0 -212
  127. package/dist/chunk-NAP6CFSO.js +0 -84
  128. package/dist/chunk-ND6MY37M.js +0 -16
  129. package/dist/chunk-NMG736UR.js +0 -683
  130. package/dist/chunk-NRAXROED.js +0 -32
  131. package/dist/chunk-NRIZR3A7.js +0 -690
  132. package/dist/chunk-NX43BG3M.js +0 -233
  133. package/dist/chunk-O645XLSI.js +0 -297
  134. package/dist/chunk-OMJD6A3S.js +0 -235
  135. package/dist/chunk-QB6SJD4T.js +0 -430
  136. package/dist/chunk-QFSTL4J3.js +0 -276
  137. package/dist/chunk-QLGDFMFX.js +0 -212
  138. package/dist/chunk-RIAAGL2E.js +0 -13
  139. package/dist/chunk-RWO5XMZ6.js +0 -86
  140. package/dist/chunk-RXRKBBSM.js +0 -149
  141. package/dist/chunk-RZOZMML6.js +0 -363
  142. package/dist/chunk-U7I7FS7T.js +0 -113
  143. package/dist/chunk-UI42RODY.js +0 -717
  144. package/dist/chunk-UTVMVSCO.js +0 -519
  145. package/dist/chunk-V6OJGLBA.js +0 -1746
  146. package/dist/chunk-W2JHVH7D.js +0 -152
  147. package/dist/chunk-WD3Y7VQN.js +0 -280
  148. package/dist/chunk-WOCTQ5MS.js +0 -303
  149. package/dist/chunk-WZR3ZUNN.js +0 -696
  150. package/dist/chunk-XGI665H7.js +0 -150
  151. package/dist/chunk-XKY65P2T.js +0 -304
  152. package/dist/chunk-Y4CQZY65.js +0 -57
  153. package/dist/chunk-YFEXKLVE.js +0 -194
  154. package/dist/chunk-YHO3HS5X.js +0 -287
  155. package/dist/chunk-YLS7AZSX.js +0 -738
  156. package/dist/chunk-ZE473AO6.js +0 -49
  157. package/dist/chunk-ZF747T3O.js +0 -644
  158. package/dist/chunk-ZHCZHZH3.js +0 -43
  159. package/dist/chunk-ZZNZX2XY.js +0 -87
  160. package/dist/constants-7QAP3VQ4.js +0 -23
  161. package/dist/dist-IY3UUMWK.js +0 -33
  162. package/dist/invariants-runner-W5RGHCSU.js +0 -27
  163. package/dist/lane-lock-6J36HD5O.js +0 -35
  164. package/dist/mem-checkpoint-core-EANG2GVN.js +0 -14
  165. package/dist/mem-signal-core-2LZ2WYHW.js +0 -19
  166. package/dist/memory-store-OLB5FO7K.js +0 -18
  167. package/dist/service-6BYCOCO5.js +0 -13
  168. package/dist/spawn-policy-resolver-NTSZYQ6R.js +0 -17
  169. package/dist/spawn-task-builder-R4E2BHSW.js +0 -22
  170. package/dist/wu-done-pr-WLFFFEPJ.js +0 -25
  171. package/dist/wu-done-validation-3J5E36FE.js +0 -30
  172. package/dist/wu-duplicate-id-detector-5S7JHELK.js +0 -232
  173. package/packs/sidekick/.turbo/turbo-test.log +0 -12
  174. package/packs/sidekick/.turbo/turbo-typecheck.log +0 -4
  175. package/packs/software-delivery/.turbo/turbo-typecheck.log +0 -4
@@ -1,392 +0,0 @@
1
- import {
2
- generateEnforceWorktreeScript,
3
- generateEnforcementHooks,
4
- generateRequireWuScript,
5
- generateWarnIncompleteScript
6
- } from "./chunk-EA3IVO64.js";
7
- import {
8
- loadTemplate
9
- } from "./chunk-HEVS5YLD.js";
10
- import {
11
- generateScriptsFromManifest
12
- } from "./chunk-KY4PGL5V.js";
13
- import {
14
- WU_OPTIONS,
15
- createWUParser,
16
- runCLI
17
- } from "./chunk-2GXVIN57.js";
18
- import {
19
- CLAUDE_HOOKS,
20
- DIRECTORIES
21
- } from "./chunk-DWMLTXKQ.js";
22
- import {
23
- LUMENFLOW_CLIENT_IDS,
24
- WORKSPACE_CONFIG_FILE_NAME,
25
- WORKSPACE_V2_KEYS
26
- } from "./chunk-V6OJGLBA.js";
27
-
28
- // src/commands/integrate.ts
29
- import * as fs from "fs";
30
- import * as path from "path";
31
- import * as yaml from "yaml";
32
- var SUPPORTED_CLIENTS = [
33
- LUMENFLOW_CLIENT_IDS.CLAUDE_CODE,
34
- LUMENFLOW_CLIENT_IDS.CURSOR,
35
- LUMENFLOW_CLIENT_IDS.CODEX_CLI
36
- ];
37
- var INTEGRATE_OPTIONS = {
38
- client: {
39
- name: "client",
40
- flags: "--client <type>",
41
- description: `Client type to integrate (${SUPPORTED_CLIENTS.join(", ")})`
42
- },
43
- sync: {
44
- name: "sync",
45
- flags: "--sync",
46
- description: "Re-scaffold vendor-agnostic pre-commit/CI delegators and sync package.json command aliases"
47
- },
48
- force: WU_OPTIONS.force
49
- };
50
- function parseIntegrateOptions() {
51
- const opts = createWUParser({
52
- name: "lumenflow-integrate",
53
- description: "Integrate LumenFlow enforcement with AI client tools",
54
- options: Object.values(INTEGRATE_OPTIONS)
55
- });
56
- return {
57
- client: opts.client ?? LUMENFLOW_CLIENT_IDS.CLAUDE_CODE,
58
- sync: opts.sync ?? false,
59
- force: opts.force ?? false
60
- };
61
- }
62
- var PRE_COMMIT_TEMPLATE_PATH = "core/.husky/pre-commit.template";
63
- var CI_TEMPLATE_PATH = "core/.github/workflows/lumenflow-ci.yml.template";
64
- var PROJECT_PRE_COMMIT_PATH = ".husky/pre-commit";
65
- var PROJECT_CI_PATH = ".github/workflows/lumenflow-ci.yml";
66
- function syncCoreEnforcementDelegators(projectDir) {
67
- const created = [];
68
- const preCommitContent = loadTemplate(PRE_COMMIT_TEMPLATE_PATH);
69
- const preCommitPath = path.join(projectDir, PROJECT_PRE_COMMIT_PATH);
70
- fs.mkdirSync(path.dirname(preCommitPath), { recursive: true });
71
- fs.writeFileSync(preCommitPath, preCommitContent, { mode: 493 });
72
- created.push(PROJECT_PRE_COMMIT_PATH);
73
- const ciContent = loadTemplate(CI_TEMPLATE_PATH);
74
- const ciPath = path.join(projectDir, PROJECT_CI_PATH);
75
- fs.mkdirSync(path.dirname(ciPath), { recursive: true });
76
- fs.writeFileSync(ciPath, ciContent, "utf-8");
77
- created.push(PROJECT_CI_PATH);
78
- return created;
79
- }
80
- function syncPackageJsonScripts(projectDir) {
81
- const packageJsonPath = path.join(projectDir, "package.json");
82
- if (!fs.existsSync(packageJsonPath)) {
83
- return { added: [], modified: false };
84
- }
85
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
86
- if (!packageJson.scripts || typeof packageJson.scripts !== "object") {
87
- packageJson.scripts = {};
88
- }
89
- const scripts = packageJson.scripts;
90
- const manifestScripts = generateScriptsFromManifest();
91
- const added = [];
92
- for (const [name, command] of Object.entries(manifestScripts)) {
93
- if (!(name in scripts)) {
94
- scripts[name] = command;
95
- added.push(name);
96
- }
97
- }
98
- const modified = added.length > 0;
99
- if (modified) {
100
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
101
- }
102
- return { added, modified };
103
- }
104
- function readClaudeSettings(projectDir) {
105
- const settingsPath = path.join(projectDir, DIRECTORIES.CLAUDE, "settings.json");
106
- if (!fs.existsSync(settingsPath)) {
107
- return {
108
- $schema: "https://json.schemastore.org/claude-code-settings.json",
109
- permissions: {
110
- allow: ["Bash", "Read", "Write", "Edit", "WebFetch", "WebSearch", "Skill"]
111
- }
112
- };
113
- }
114
- try {
115
- const content = fs.readFileSync(settingsPath, "utf-8");
116
- return JSON.parse(content);
117
- } catch {
118
- return {
119
- $schema: "https://json.schemastore.org/claude-code-settings.json"
120
- };
121
- }
122
- }
123
- function mergeHooksIntoSettings(existing, generated) {
124
- const result = { ...existing };
125
- if (!result.hooks) {
126
- result.hooks = {};
127
- }
128
- if (generated.preToolUse) {
129
- if (!result.hooks.PreToolUse) {
130
- result.hooks.PreToolUse = [];
131
- }
132
- for (const newHook of generated.preToolUse) {
133
- const existingIndex = result.hooks.PreToolUse.findIndex((h) => h.matcher === newHook.matcher);
134
- if (existingIndex >= 0) {
135
- const existing2 = result.hooks.PreToolUse[existingIndex];
136
- for (const hook of newHook.hooks) {
137
- const isDuplicate = existing2.hooks.some((h) => h.command === hook.command);
138
- if (!isDuplicate) {
139
- existing2.hooks.push(hook);
140
- }
141
- }
142
- } else {
143
- result.hooks.PreToolUse.push(newHook);
144
- }
145
- }
146
- }
147
- if (generated.stop) {
148
- if (!result.hooks.Stop) {
149
- result.hooks.Stop = [];
150
- }
151
- for (const newHook of generated.stop) {
152
- const existingIndex = result.hooks.Stop.findIndex((h) => h.matcher === newHook.matcher);
153
- if (existingIndex >= 0) {
154
- const existing2 = result.hooks.Stop[existingIndex];
155
- for (const hook of newHook.hooks) {
156
- const isDuplicate = existing2.hooks.some((h) => h.command === hook.command);
157
- if (!isDuplicate) {
158
- existing2.hooks.push(hook);
159
- }
160
- }
161
- } else {
162
- result.hooks.Stop.push(newHook);
163
- }
164
- }
165
- }
166
- return result;
167
- }
168
- async function integrateClaudeCode(projectDir, config) {
169
- const enforcement = config.enforcement;
170
- const created = [];
171
- if (!enforcement?.hooks) {
172
- console.log("[integrate] Enforcement hooks not enabled, skipping");
173
- return created;
174
- }
175
- const hooksDir = path.join(projectDir, DIRECTORIES.CLAUDE_HOOKS);
176
- if (!fs.existsSync(hooksDir)) {
177
- fs.mkdirSync(hooksDir, { recursive: true });
178
- console.log("[integrate] Created hooks directory");
179
- }
180
- const generatedHooks = generateEnforcementHooks({
181
- block_outside_worktree: enforcement.block_outside_worktree ?? false,
182
- require_wu_for_edits: enforcement.require_wu_for_edits ?? false,
183
- warn_on_stop_without_wu_done: enforcement.warn_on_stop_without_wu_done ?? false
184
- });
185
- if (enforcement.block_outside_worktree) {
186
- const scriptPath = path.join(hooksDir, CLAUDE_HOOKS.SCRIPTS.ENFORCE_WORKTREE);
187
- fs.writeFileSync(scriptPath, generateEnforceWorktreeScript({ projectRoot: projectDir }), {
188
- mode: 493
189
- });
190
- console.log(`[integrate] Generated ${CLAUDE_HOOKS.SCRIPTS.ENFORCE_WORKTREE}`);
191
- created.push(path.join(DIRECTORIES.CLAUDE_HOOKS, CLAUDE_HOOKS.SCRIPTS.ENFORCE_WORKTREE));
192
- }
193
- if (enforcement.require_wu_for_edits) {
194
- const scriptPath = path.join(hooksDir, CLAUDE_HOOKS.SCRIPTS.REQUIRE_WU);
195
- fs.writeFileSync(scriptPath, generateRequireWuScript(), { mode: 493 });
196
- console.log(`[integrate] Generated ${CLAUDE_HOOKS.SCRIPTS.REQUIRE_WU}`);
197
- created.push(path.join(DIRECTORIES.CLAUDE_HOOKS, CLAUDE_HOOKS.SCRIPTS.REQUIRE_WU));
198
- }
199
- if (enforcement.warn_on_stop_without_wu_done) {
200
- const scriptPath = path.join(hooksDir, CLAUDE_HOOKS.SCRIPTS.WARN_INCOMPLETE);
201
- fs.writeFileSync(scriptPath, generateWarnIncompleteScript(), { mode: 493 });
202
- console.log(`[integrate] Generated ${CLAUDE_HOOKS.SCRIPTS.WARN_INCOMPLETE}`);
203
- created.push(path.join(DIRECTORIES.CLAUDE_HOOKS, CLAUDE_HOOKS.SCRIPTS.WARN_INCOMPLETE));
204
- }
205
- const existingSettings = readClaudeSettings(projectDir);
206
- const updatedSettings = mergeHooksIntoSettings(existingSettings, generatedHooks);
207
- const settingsPath = path.join(projectDir, DIRECTORIES.CLAUDE, "settings.json");
208
- fs.writeFileSync(settingsPath, JSON.stringify(updatedSettings, null, 2) + "\n", "utf-8");
209
- console.log("[integrate] Updated settings.json");
210
- return created;
211
- }
212
- function readWorkspaceSoftwareDeliveryConfig(projectDir) {
213
- const configPath = path.join(projectDir, WORKSPACE_CONFIG_FILE_NAME);
214
- if (!fs.existsSync(configPath)) {
215
- return null;
216
- }
217
- try {
218
- const content = fs.readFileSync(configPath, "utf-8");
219
- const workspaceDoc = yaml.parse(content);
220
- if (!workspaceDoc || typeof workspaceDoc !== "object") {
221
- return null;
222
- }
223
- const workspace = workspaceDoc;
224
- const softwareDelivery = workspace[WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY];
225
- if (!softwareDelivery || typeof softwareDelivery !== "object") {
226
- return null;
227
- }
228
- return softwareDelivery;
229
- } catch {
230
- return null;
231
- }
232
- }
233
- function readEnforcementConfig(projectDir) {
234
- const softwareDelivery = readWorkspaceSoftwareDeliveryConfig(projectDir);
235
- return softwareDelivery?.agents?.clients?.[LUMENFLOW_CLIENT_IDS.CLAUDE_CODE]?.enforcement ?? null;
236
- }
237
- var CURSOR_RECOVERY_RULES = `# LumenFlow Context Recovery
238
-
239
- ## On Session Start
240
-
241
- When starting a new session or resuming work, always check for pending recovery context:
242
-
243
- \`\`\`bash
244
- # Check for recovery files
245
- ls .lumenflow/state/recovery-pending-*.md 2>/dev/null
246
- \`\`\`
247
-
248
- If recovery files exist:
249
-
250
- 1. Read the recovery file contents \u2014 they contain your last checkpoint, acceptance criteria, and code paths
251
- 2. Run \`pnpm mem:recover --wu WU-XXX\` (replace WU-XXX with the WU ID from the filename) for the latest context
252
- 3. Continue working based on the recovery context
253
-
254
- ## Context Loss Prevention
255
-
256
- Before any long operation that might lose context:
257
-
258
- \`\`\`bash
259
- pnpm mem:checkpoint "description of current progress" --wu WU-XXX
260
- \`\`\`
261
-
262
- ## Recovery Command Reference
263
-
264
- | Command | Purpose |
265
- | ------------------------------------------- | ---------------------------------- |
266
- | \`pnpm mem:recover --wu WU-XXX\` | Generate recovery context for a WU |
267
- | \`pnpm wu:brief --id WU-XXX --client cursor\` | Generate full handoff prompt |
268
- | \`pnpm wu:status --id WU-XXX\` | Check WU status and location |
269
- | \`pnpm mem:checkpoint\` | Save progress checkpoint |
270
- `;
271
- var AGENTS_RECOVERY_SECTION = `
272
- ---
273
-
274
- ## Context Recovery (WU-2157)
275
-
276
- If you are resuming work or have lost context, check for recovery files:
277
-
278
- \`\`\`bash
279
- # Check for pending recovery
280
- ls .lumenflow/state/recovery-pending-*.md 2>/dev/null
281
-
282
- # Generate fresh recovery context
283
- pnpm mem:recover --wu WU-XXX
284
-
285
- # Or generate a full handoff prompt
286
- pnpm wu:brief --id WU-XXX --client codex-cli
287
- \`\`\`
288
-
289
- Recovery files contain your last checkpoint, acceptance criteria, code paths, and changed files.
290
- Always save checkpoints before long operations: \`pnpm mem:checkpoint "progress note" --wu WU-XXX\`
291
- `;
292
- function integrateCursor(projectDir) {
293
- const created = [];
294
- const rulesDir = path.join(projectDir, ".cursor", "rules");
295
- if (!fs.existsSync(rulesDir)) {
296
- fs.mkdirSync(rulesDir, { recursive: true });
297
- console.log("[integrate] Created .cursor/rules/ directory");
298
- }
299
- const recoveryRulesPath = path.join(rulesDir, "lumenflow-recovery.md");
300
- fs.writeFileSync(recoveryRulesPath, CURSOR_RECOVERY_RULES, "utf-8");
301
- console.log("[integrate] Generated .cursor/rules/lumenflow-recovery.md");
302
- created.push(".cursor/rules/lumenflow-recovery.md");
303
- return created;
304
- }
305
- function integrateCodexCli(projectDir) {
306
- const created = [];
307
- const agentsPath = path.join(projectDir, "AGENTS.md");
308
- if (!fs.existsSync(agentsPath)) {
309
- console.log("[integrate] AGENTS.md not found, skipping Codex integration");
310
- return created;
311
- }
312
- const content = fs.readFileSync(agentsPath, "utf-8");
313
- if (content.includes("## Context Recovery (WU-2157)")) {
314
- console.log("[integrate] AGENTS.md already contains recovery section, skipping");
315
- return created;
316
- }
317
- fs.writeFileSync(agentsPath, content + AGENTS_RECOVERY_SECTION, "utf-8");
318
- console.log("[integrate] Appended recovery section to AGENTS.md");
319
- created.push("AGENTS.md");
320
- return created;
321
- }
322
- async function main() {
323
- const opts = parseIntegrateOptions();
324
- const projectDir = process.cwd();
325
- if (opts.sync) {
326
- const synced = syncCoreEnforcementDelegators(projectDir);
327
- for (const file of synced) {
328
- console.log(`[integrate] Synced ${file}`);
329
- }
330
- const scriptSync = syncPackageJsonScripts(projectDir);
331
- if (scriptSync.modified) {
332
- console.log(
333
- `[integrate] Added ${scriptSync.added.length} command alias(es): ${scriptSync.added.join(", ")}`
334
- );
335
- } else {
336
- console.log("[integrate] package.json command aliases already up to date");
337
- }
338
- }
339
- switch (opts.client) {
340
- case LUMENFLOW_CLIENT_IDS.CLAUDE_CODE: {
341
- const enforcement = readEnforcementConfig(projectDir);
342
- if (!enforcement) {
343
- console.log(
344
- `[integrate] No enforcement config found in ${WORKSPACE_CONFIG_FILE_NAME} ${WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY}.agents.clients.${LUMENFLOW_CLIENT_IDS.CLAUDE_CODE}`
345
- );
346
- console.log("[integrate] Add this to your workspace config to enable enforcement hooks:");
347
- console.log(`
348
- ${WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY}:
349
- agents:
350
- clients:
351
- ${LUMENFLOW_CLIENT_IDS.CLAUDE_CODE}:
352
- enforcement:
353
- hooks: true
354
- block_outside_worktree: true
355
- require_wu_for_edits: true
356
- warn_on_stop_without_wu_done: true
357
- `);
358
- return;
359
- }
360
- await integrateClaudeCode(projectDir, { enforcement });
361
- console.log("[integrate] Claude Code integration complete");
362
- break;
363
- }
364
- case LUMENFLOW_CLIENT_IDS.CURSOR: {
365
- integrateCursor(projectDir);
366
- console.log("[integrate] Cursor integration complete");
367
- break;
368
- }
369
- case LUMENFLOW_CLIENT_IDS.CODEX_CLI: {
370
- integrateCodexCli(projectDir);
371
- console.log("[integrate] Codex CLI integration complete");
372
- break;
373
- }
374
- default:
375
- console.error(`[integrate] Unsupported client: ${opts.client}`);
376
- console.error(`[integrate] Supported clients: ${SUPPORTED_CLIENTS.join(", ")}`);
377
- process.exit(1);
378
- }
379
- }
380
- if (import.meta.main) {
381
- void runCLI(main);
382
- }
383
-
384
- export {
385
- parseIntegrateOptions,
386
- syncCoreEnforcementDelegators,
387
- syncPackageJsonScripts,
388
- integrateClaudeCode,
389
- integrateCursor,
390
- integrateCodexCli,
391
- main
392
- };
@@ -1,240 +0,0 @@
1
- import {
2
- SIGNAL_FILE_NAME,
3
- SIGNAL_RECEIPTS_FILE_NAME
4
- } from "./chunk-OMJD6A3S.js";
5
- import {
6
- LUMENFLOW_MEMORY_PATHS
7
- } from "./chunk-4N74J3UT.js";
8
- import {
9
- MS_PER_DAY
10
- } from "./chunk-V6OJGLBA.js";
11
- import {
12
- ErrorCodes,
13
- createError
14
- } from "./chunk-RXRKBBSM.js";
15
-
16
- // ../memory/dist/signal-cleanup-core.js
17
- import fs from "fs/promises";
18
- import path from "path";
19
- import { createRequire } from "module";
20
- var require2 = createRequire(import.meta.url);
21
- var ms = require2("ms");
22
- var DEFAULT_SIGNAL_CLEANUP_CONFIG = {
23
- ttl: 7 * MS_PER_DAY,
24
- unreadTtl: 30 * MS_PER_DAY,
25
- maxEntries: 500
26
- };
27
- function parseSignalTtl(ttlString) {
28
- if (!ttlString || typeof ttlString !== "string") {
29
- throw createError(ErrorCodes.INVALID_DURATION, "Invalid TTL format: TTL string is required");
30
- }
31
- const trimmed = ttlString.trim();
32
- if (!trimmed) {
33
- throw createError(ErrorCodes.INVALID_DURATION, "Invalid TTL format: TTL string is required");
34
- }
35
- const result = ms(trimmed);
36
- if (result == null || result <= 0) {
37
- throw createError(ErrorCodes.INVALID_DURATION, `Invalid TTL format: "${ttlString}" is not a valid duration`);
38
- }
39
- return result;
40
- }
41
- function isSignalExpired(signal, ttlMs, now) {
42
- if (!signal.created_at) {
43
- return false;
44
- }
45
- const createdAt = new Date(signal.created_at).getTime();
46
- if (Number.isNaN(createdAt)) {
47
- return false;
48
- }
49
- const age = now - createdAt;
50
- return age > ttlMs;
51
- }
52
- function shouldRemoveSignal(signal, config, context) {
53
- const { now, activeWuIds } = context;
54
- if (signal.wu_id && activeWuIds.has(signal.wu_id)) {
55
- return { remove: false, reason: "active-wu-protected" };
56
- }
57
- if (signal.read) {
58
- if (isSignalExpired(signal, config.ttl, now)) {
59
- return { remove: true, reason: "ttl-expired" };
60
- }
61
- } else {
62
- if (isSignalExpired(signal, config.unreadTtl, now)) {
63
- return { remove: true, reason: "unread-ttl-expired" };
64
- }
65
- }
66
- return { remove: false, reason: "within-ttl" };
67
- }
68
- function estimateSignalBytes(signal) {
69
- return JSON.stringify(signal).length + 1;
70
- }
71
- function getCompactionRatio(removedCount, totalCount) {
72
- if (totalCount === 0) {
73
- return 0;
74
- }
75
- return removedCount / totalCount;
76
- }
77
- function getSignalsPath(baseDir) {
78
- return path.join(baseDir, LUMENFLOW_MEMORY_PATHS.MEMORY_DIR, SIGNAL_FILE_NAME);
79
- }
80
- function getReceiptsPath(baseDir) {
81
- return path.join(baseDir, LUMENFLOW_MEMORY_PATHS.MEMORY_DIR, SIGNAL_RECEIPTS_FILE_NAME);
82
- }
83
- async function loadAllReceipts(baseDir) {
84
- const receiptsPath = getReceiptsPath(baseDir);
85
- try {
86
- const content = await fs.readFile(receiptsPath, { encoding: "utf-8" });
87
- const lines = content.split("\n").filter((line) => line.trim());
88
- return lines.map((line) => JSON.parse(line));
89
- } catch (err) {
90
- const error = err;
91
- if (error.code === "ENOENT") {
92
- return [];
93
- }
94
- throw error;
95
- }
96
- }
97
- async function writeReceipts(baseDir, receipts) {
98
- const receiptsPath = getReceiptsPath(baseDir);
99
- const content = receipts.map((r) => JSON.stringify(r)).join("\n") + (receipts.length > 0 ? "\n" : "");
100
- await fs.writeFile(receiptsPath, content, { encoding: "utf-8" });
101
- }
102
- async function loadAllSignals(baseDir) {
103
- const signalsPath = getSignalsPath(baseDir);
104
- try {
105
- const content = await fs.readFile(signalsPath, { encoding: "utf-8" });
106
- const lines = content.split("\n").filter((line) => line.trim());
107
- return lines.map((line) => JSON.parse(line));
108
- } catch (err) {
109
- const error = err;
110
- if (error.code === "ENOENT") {
111
- return [];
112
- }
113
- throw error;
114
- }
115
- }
116
- async function writeSignals(baseDir, signals) {
117
- const signalsPath = getSignalsPath(baseDir);
118
- const content = signals.map((s) => JSON.stringify(s)).join("\n") + (signals.length > 0 ? "\n" : "");
119
- await fs.writeFile(signalsPath, content, { encoding: "utf-8" });
120
- }
121
- async function defaultGetActiveWuIds() {
122
- return /* @__PURE__ */ new Set();
123
- }
124
- function buildCleanupConfig(options) {
125
- const { ttl, ttlMs: providedTtlMs, unreadTtl, unreadTtlMs: providedUnreadTtlMs, maxEntries } = options;
126
- let ttlMs = providedTtlMs ?? DEFAULT_SIGNAL_CLEANUP_CONFIG.ttl;
127
- if (ttl && !providedTtlMs) {
128
- ttlMs = parseSignalTtl(ttl);
129
- }
130
- let unreadTtlMs = providedUnreadTtlMs ?? DEFAULT_SIGNAL_CLEANUP_CONFIG.unreadTtl;
131
- if (unreadTtl && !providedUnreadTtlMs) {
132
- unreadTtlMs = parseSignalTtl(unreadTtl);
133
- }
134
- return {
135
- ttl: ttlMs,
136
- unreadTtl: unreadTtlMs,
137
- maxEntries: maxEntries ?? DEFAULT_SIGNAL_CLEANUP_CONFIG.maxEntries
138
- };
139
- }
140
- function processSignalsForTtl(signals, config, context) {
141
- const state = {
142
- removedIds: [],
143
- retainedIds: [],
144
- retainedSignals: [],
145
- bytesFreed: 0,
146
- breakdown: {
147
- ttlExpired: 0,
148
- unreadTtlExpired: 0,
149
- countLimitExceeded: 0,
150
- activeWuProtected: 0
151
- }
152
- };
153
- for (const signal of signals) {
154
- const decision = shouldRemoveSignal(signal, config, context);
155
- processSignalDecision(signal, decision, state);
156
- }
157
- return state;
158
- }
159
- function processSignalDecision(signal, decision, state) {
160
- if (decision.remove) {
161
- state.removedIds.push(signal.id);
162
- state.bytesFreed += estimateSignalBytes(signal);
163
- updateBreakdownForRemoval(decision.reason, state.breakdown);
164
- } else {
165
- state.retainedIds.push(signal.id);
166
- state.retainedSignals.push(signal);
167
- if (decision.reason === "active-wu-protected") {
168
- state.breakdown.activeWuProtected++;
169
- }
170
- }
171
- }
172
- function updateBreakdownForRemoval(reason, breakdown) {
173
- if (reason === "ttl-expired") {
174
- breakdown.ttlExpired++;
175
- } else if (reason === "unread-ttl-expired") {
176
- breakdown.unreadTtlExpired++;
177
- }
178
- }
179
- function applyCountPruning(state, maxEntries) {
180
- if (state.retainedSignals.length <= maxEntries) {
181
- return;
182
- }
183
- state.retainedSignals.sort((a, b) => {
184
- const aTime = new Date(a.created_at).getTime();
185
- const bTime = new Date(b.created_at).getTime();
186
- return aTime - bTime;
187
- });
188
- const toRemove = state.retainedSignals.length - maxEntries;
189
- for (let i = 0; i < toRemove; i++) {
190
- const signal = state.retainedSignals[i];
191
- if (!signal)
192
- continue;
193
- const idIndex = state.retainedIds.indexOf(signal.id);
194
- if (idIndex !== -1) {
195
- state.retainedIds.splice(idIndex, 1);
196
- }
197
- state.removedIds.push(signal.id);
198
- state.bytesFreed += estimateSignalBytes(signal);
199
- state.breakdown.countLimitExceeded++;
200
- }
201
- state.retainedSignals.splice(0, toRemove);
202
- }
203
- async function cleanupSignals(baseDir, options = {}) {
204
- const { dryRun = false, now = Date.now(), getActiveWuIds = defaultGetActiveWuIds } = options;
205
- const config = buildCleanupConfig(options);
206
- const signals = await loadAllSignals(baseDir);
207
- const activeWuIds = await getActiveWuIds();
208
- const receipts = await loadAllReceipts(baseDir);
209
- const receiptSignalIds = new Set(receipts.map((r) => r.signal_id));
210
- for (const signal of signals) {
211
- if (!signal.read && receiptSignalIds.has(signal.id)) {
212
- signal.read = true;
213
- }
214
- }
215
- const state = processSignalsForTtl(signals, config, { now, activeWuIds });
216
- applyCountPruning(state, config.maxEntries);
217
- const compactionRatio = getCompactionRatio(state.removedIds.length, signals.length);
218
- const baseResult = {
219
- success: true,
220
- removedIds: state.removedIds,
221
- retainedIds: state.retainedIds,
222
- bytesFreed: state.bytesFreed,
223
- compactionRatio,
224
- breakdown: state.breakdown
225
- };
226
- if (dryRun) {
227
- return { ...baseResult, dryRun: true };
228
- }
229
- if (state.removedIds.length > 0) {
230
- await writeSignals(baseDir, state.retainedSignals);
231
- const retainedIdSet = new Set(state.retainedIds);
232
- const retainedReceipts = receipts.filter((r) => retainedIdSet.has(r.signal_id));
233
- await writeReceipts(baseDir, retainedReceipts);
234
- }
235
- return baseResult;
236
- }
237
-
238
- export {
239
- cleanupSignals
240
- };