@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,67 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * @file generators/warn-incomplete.ts
5
+ * Generate the warn-incomplete.sh hook script content (WU-1367).
6
+ *
7
+ * Extracted from enforcement-generator.ts by WU-1645.
8
+ */
9
+ /**
10
+ * Generate the warn-incomplete.sh hook script content.
11
+ *
12
+ * This Stop hook warns when session ends without wu:done.
13
+ * Always exits 0 (warning only, never blocks).
14
+ */
15
+ export function generateWarnIncompleteScript() {
16
+ // Note: Shell variable escapes (\$, \") are intentional for the generated bash script
17
+ /* eslint-disable no-useless-escape */
18
+ return `#!/bin/bash
19
+ #
20
+ # warn-incomplete.sh (WU-1367)
21
+ #
22
+ # Stop hook that warns when session ends without wu:done.
23
+ # This is advisory only - never blocks session termination.
24
+ #
25
+ # Exit codes:
26
+ # 0 = Always (warnings only)
27
+ #
28
+
29
+ SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
30
+
31
+ if [[ -z "\${CLAUDE_PROJECT_DIR:-}" ]]; then
32
+ exit 0
33
+ fi
34
+
35
+ MAIN_REPO_PATH="\$CLAUDE_PROJECT_DIR"
36
+ WORKTREES_DIR="\${MAIN_REPO_PATH}/worktrees"
37
+
38
+ # Check for active worktrees
39
+ if [[ ! -d "\$WORKTREES_DIR" ]]; then
40
+ exit 0
41
+ fi
42
+
43
+ WORKTREE_COUNT=\$(find "\$WORKTREES_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)
44
+ if [[ "\$WORKTREE_COUNT" -eq 0 ]]; then
45
+ exit 0
46
+ fi
47
+
48
+ # Get active worktree names
49
+ ACTIVE_WORKTREES=\$(find "\$WORKTREES_DIR" -mindepth 1 -maxdepth 1 -type d -printf '%f\\n' 2>/dev/null | head -5 | tr '\\n' ', ' | sed 's/,\$//')
50
+
51
+ echo "" >&2
52
+ echo "=== Session Completion Reminder ===" >&2
53
+ echo "" >&2
54
+ echo "You have active worktrees: \$ACTIVE_WORKTREES" >&2
55
+ echo "" >&2
56
+ echo "If your work is complete, remember to run:" >&2
57
+ echo " pnpm wu:prep --id WU-XXXX (from worktree)" >&2
58
+ echo " pnpm wu:done --id WU-XXXX (from main)" >&2
59
+ echo "" >&2
60
+ echo "If work is incomplete, it will be preserved in the worktree." >&2
61
+ echo "====================================" >&2
62
+
63
+ exit 0
64
+ `;
65
+ /* eslint-enable no-useless-escape */
66
+ }
67
+ //# sourceMappingURL=warn-incomplete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warn-incomplete.js","sourceRoot":"","sources":["../../../src/hooks/generators/warn-incomplete.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yCAAyC;AAEzC;;;;;GAKG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B;IAC1C,sFAAsF;IACtF,sCAAsC;IACtC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CR,CAAC;IACA,qCAAqC;AACvC,CAAC"}
@@ -0,0 +1,10 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * @file hooks/index.ts
5
+ * Claude Code enforcement hooks module (WU-1367)
6
+ */
7
+ export * from './enforcement-generator.js';
8
+ export * from './enforcement-checks.js';
9
+ export * from './enforcement-sync.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yCAAyC;AAEzC;;;GAGG;AAEH,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yCAAyC;AAEzC;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE7D,uDAAuD;AACvD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,aAAa,GACd,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,232 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * @file init-detection.ts
5
+ * Detection helpers for LumenFlow init command (WU-1644)
6
+ *
7
+ * Extracted from init.ts -- environment detection, prerequisite checks,
8
+ * git state inspection, and docs structure detection.
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+ import { execFileSync } from 'node:child_process';
13
+ import { LUMENFLOW_CLIENT_IDS } from '@lumenflow/core';
14
+ const DEFAULT_CLIENT_CLAUDE = LUMENFLOW_CLIENT_IDS.CLAUDE_CODE;
15
+ /**
16
+ * WU-1177: Detect IDE environment from environment variables
17
+ * Auto-detects which AI coding assistant is running
18
+ */
19
+ export function detectIDEEnvironment() {
20
+ // Claude Code detection (highest priority - most specific)
21
+ if (process.env.CLAUDE_PROJECT_DIR || process.env.CLAUDE_CODE) {
22
+ return 'claude';
23
+ }
24
+ // Cursor detection
25
+ const cursorVars = Object.keys(process.env).filter((key) => key.startsWith('CURSOR_'));
26
+ if (cursorVars.length > 0) {
27
+ return 'cursor';
28
+ }
29
+ // Windsurf detection
30
+ const windsurfVars = Object.keys(process.env).filter((key) => key.startsWith('WINDSURF_'));
31
+ if (windsurfVars.length > 0) {
32
+ return 'windsurf';
33
+ }
34
+ // VS Code detection (lowest priority - most generic)
35
+ const vscodeVars = Object.keys(process.env).filter((key) => key.startsWith('VSCODE_'));
36
+ if (vscodeVars.length > 0) {
37
+ return 'vscode';
38
+ }
39
+ return undefined;
40
+ }
41
+ /**
42
+ * Get command version safely using execFileSync
43
+ */
44
+ function getCommandVersion(command, args) {
45
+ try {
46
+ const output = execFileSync(command, args, {
47
+ encoding: 'utf-8',
48
+ stdio: ['pipe', 'pipe', 'pipe'],
49
+ }).trim();
50
+ return output;
51
+ }
52
+ catch {
53
+ return 'not found';
54
+ }
55
+ }
56
+ /**
57
+ * Parse semver version string to compare
58
+ */
59
+ function parseVersion(versionStr) {
60
+ // WU-1968: Removed ^ anchor so "git version 2.43.0" is parsed correctly.
61
+ // The previous ^v? pattern required the string to start with a digit or "v",
62
+ // but `git --version` returns "git version X.Y.Z" which starts with "git".
63
+ // eslint-disable-next-line security/detect-unsafe-regex -- static semver pattern; no backtracking risk
64
+ const match = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(versionStr);
65
+ if (!match) {
66
+ return [0, 0, 0];
67
+ }
68
+ return [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3] || '0', 10)];
69
+ }
70
+ /**
71
+ * Compare versions: returns true if actual >= required
72
+ */
73
+ function compareVersions(actual, required) {
74
+ const actualParts = parseVersion(actual);
75
+ const requiredParts = parseVersion(required);
76
+ for (let i = 0; i < 3; i++) {
77
+ if (actualParts[i] > requiredParts[i]) {
78
+ return true;
79
+ }
80
+ if (actualParts[i] < requiredParts[i]) {
81
+ return false;
82
+ }
83
+ }
84
+ return true;
85
+ }
86
+ /**
87
+ * WU-1177: Check prerequisite versions
88
+ * Non-blocking - returns results but doesn't fail init
89
+ */
90
+ export function checkPrerequisites() {
91
+ const nodeVersion = getCommandVersion('node', ['--version']);
92
+ const pnpmVersion = getCommandVersion('pnpm', ['--version']);
93
+ const gitVersion = getCommandVersion('git', ['--version']);
94
+ const requiredNode = '22.0.0';
95
+ const requiredPnpm = '9.0.0';
96
+ const requiredGit = '2.0.0';
97
+ const nodeOk = nodeVersion !== 'not found' && compareVersions(nodeVersion, requiredNode);
98
+ const pnpmOk = pnpmVersion !== 'not found' && compareVersions(pnpmVersion, requiredPnpm);
99
+ const gitOk = gitVersion !== 'not found' && compareVersions(gitVersion, requiredGit);
100
+ return {
101
+ node: {
102
+ passed: nodeOk,
103
+ version: nodeVersion,
104
+ required: `>=${requiredNode}`,
105
+ message: nodeOk ? undefined : `Node.js ${requiredNode}+ required`,
106
+ },
107
+ pnpm: {
108
+ passed: pnpmOk,
109
+ version: pnpmVersion,
110
+ required: `>=${requiredPnpm}`,
111
+ message: pnpmOk ? undefined : `pnpm ${requiredPnpm}+ required`,
112
+ },
113
+ git: {
114
+ passed: gitOk,
115
+ version: gitVersion,
116
+ required: `>=${requiredGit}`,
117
+ message: gitOk ? undefined : `Git ${requiredGit}+ required`,
118
+ },
119
+ };
120
+ }
121
+ /**
122
+ * WU-1309: Get docs paths based on structure type
123
+ */
124
+ export function getDocsPath(structure) {
125
+ if (structure === 'simple') {
126
+ return {
127
+ operations: 'docs',
128
+ tasks: 'docs/tasks',
129
+ onboarding: 'docs/_frameworks/lumenflow/agent/onboarding',
130
+ quickRefLink: 'docs/_frameworks/lumenflow/agent/onboarding/quick-ref-commands.md',
131
+ };
132
+ }
133
+ // arc42 structure
134
+ return {
135
+ operations: 'docs/04-operations',
136
+ tasks: 'docs/04-operations/tasks',
137
+ onboarding: 'docs/04-operations/_frameworks/lumenflow/agent/onboarding',
138
+ quickRefLink: 'docs/04-operations/_frameworks/lumenflow/agent/onboarding/quick-ref-commands.md',
139
+ };
140
+ }
141
+ /**
142
+ * WU-1309: Detect existing docs structure or return default
143
+ * Auto-detects arc42 when docs/04-operations or UnsafeAny numbered dir (01-*, 02-*, etc.) exists
144
+ */
145
+ export function detectDocsStructure(targetDir) {
146
+ const docsDir = path.join(targetDir, 'docs');
147
+ if (!fs.existsSync(docsDir)) {
148
+ return 'simple';
149
+ }
150
+ // Check for arc42 numbered directories (01-*, 02-*, ..., 04-operations, etc.)
151
+ const entries = fs.readdirSync(docsDir);
152
+ const hasNumberedDir = entries.some((entry) => /^\d{2}-/.test(entry));
153
+ if (hasNumberedDir) {
154
+ return 'arc42';
155
+ }
156
+ return 'simple';
157
+ }
158
+ /**
159
+ * Detect default client from environment
160
+ */
161
+ export function detectDefaultClient() {
162
+ if (process.env.CLAUDE_PROJECT_DIR || process.env.CLAUDE_CODE) {
163
+ return DEFAULT_CLIENT_CLAUDE;
164
+ }
165
+ return 'none';
166
+ }
167
+ /**
168
+ * WU-1364: Check if directory is a git repository
169
+ */
170
+ export function isGitRepo(targetDir) {
171
+ try {
172
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- git resolved from PATH; CLI tool requires git
173
+ execFileSync('git', ['rev-parse', '--git-dir'], {
174
+ cwd: targetDir,
175
+ stdio: 'pipe',
176
+ });
177
+ return true;
178
+ }
179
+ catch {
180
+ return false;
181
+ }
182
+ }
183
+ /**
184
+ * WU-1364: Check if git repo has UnsafeAny commits
185
+ */
186
+ export function hasGitCommits(targetDir) {
187
+ try {
188
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- git resolved from PATH; CLI tool requires git
189
+ execFileSync('git', ['rev-parse', 'HEAD'], {
190
+ cwd: targetDir,
191
+ stdio: 'pipe',
192
+ });
193
+ return true;
194
+ }
195
+ catch {
196
+ return false;
197
+ }
198
+ }
199
+ /**
200
+ * WU-1364: Check if git repo has an origin remote
201
+ */
202
+ export function hasOriginRemote(targetDir) {
203
+ try {
204
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- git resolved from PATH; CLI tool requires git
205
+ const result = execFileSync('git', ['remote', 'get-url', 'origin'], {
206
+ cwd: targetDir,
207
+ encoding: 'utf-8',
208
+ stdio: 'pipe',
209
+ });
210
+ return result.trim().length > 0;
211
+ }
212
+ catch {
213
+ return false;
214
+ }
215
+ }
216
+ /**
217
+ * WU-1364: Detect git state and return config overrides
218
+ * Returns requireRemote: false if no origin remote is configured
219
+ */
220
+ export function detectGitStateConfig(targetDir) {
221
+ // If not a git repo, default to local-only mode for safety
222
+ if (!isGitRepo(targetDir)) {
223
+ return { requireRemote: false };
224
+ }
225
+ // If git repo but no origin remote, set requireRemote: false
226
+ if (!hasOriginRemote(targetDir)) {
227
+ return { requireRemote: false };
228
+ }
229
+ // Has origin remote - use default (requireRemote: true)
230
+ return null;
231
+ }
232
+ //# sourceMappingURL=init-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-detection.js","sourceRoot":"","sources":["../src/init-detection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * @file init-lane-validation.ts
5
+ * Lane config validation against inference hierarchy.
6
+ *
7
+ * WU-1745: Validate lane config against inference hierarchy at init time
8
+ *
9
+ * Cross-checks lane definitions in workspace.yaml software_delivery against
10
+ * .lumenflow.lane-inference.yaml parents. Catches invalid parent names
11
+ * (e.g., "Foundation: Core" when "Foundation" is not a valid parent)
12
+ * at init time instead of deferring to wu:create.
13
+ */
14
+ import * as fs from 'node:fs';
15
+ import * as path from 'node:path';
16
+ import * as yaml from 'yaml';
17
+ import { WORKSPACE_CONFIG_FILE_NAME } from '@lumenflow/core/config';
18
+ import { WORKSPACE_V2_KEYS } from '@lumenflow/core/config-schema';
19
+ /** Separator between parent and sublane in lane names */
20
+ const LANE_NAME_SEPARATOR = ': ';
21
+ const SOFTWARE_DELIVERY_KEY = WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY;
22
+ /**
23
+ * Extract the parent name from a "Parent: Sublane" lane name.
24
+ *
25
+ * @param laneName - Lane name in "Parent: Sublane" format
26
+ * @returns The parent portion, or null if no separator found
27
+ */
28
+ function extractParentName(laneName) {
29
+ const separatorIndex = laneName.indexOf(LANE_NAME_SEPARATOR);
30
+ if (separatorIndex === -1) {
31
+ return null;
32
+ }
33
+ return laneName.substring(0, separatorIndex);
34
+ }
35
+ /**
36
+ * Validate lane definitions from config against valid inference hierarchy parents.
37
+ *
38
+ * Checks that each lane's parent (the part before ": ") exists as a top-level
39
+ * key in the lane inference hierarchy.
40
+ *
41
+ * @param configLanes - Lane definitions from workspace.yaml software_delivery
42
+ * @param inferenceParents - Valid parent names from .lumenflow.lane-inference.yaml
43
+ * @returns Validation result with warnings and invalid lane names
44
+ */
45
+ export function validateLaneConfigAgainstInference(configLanes, inferenceParents) {
46
+ const warnings = [];
47
+ const invalidLanes = [];
48
+ if (configLanes.length === 0) {
49
+ return { warnings, invalidLanes };
50
+ }
51
+ const validParentSet = new Set(inferenceParents);
52
+ for (const lane of configLanes) {
53
+ const parent = extractParentName(lane.name);
54
+ if (parent === null) {
55
+ // Lane name doesn't use "Parent: Sublane" format
56
+ warnings.push(`Lane "${lane.name}" does not use the required "Parent: Sublane" format. ` +
57
+ `Valid parent names: ${inferenceParents.join(', ')}`);
58
+ invalidLanes.push(lane.name);
59
+ continue;
60
+ }
61
+ if (!validParentSet.has(parent)) {
62
+ warnings.push(`Lane "${lane.name}" uses invalid parent "${parent}". ` +
63
+ `Valid parent names in lane-inference hierarchy: ${inferenceParents.join(', ')}`);
64
+ invalidLanes.push(lane.name);
65
+ }
66
+ }
67
+ return { warnings, invalidLanes };
68
+ }
69
+ /**
70
+ * Extract top-level parent names from a lane inference YAML file.
71
+ *
72
+ * The lane inference file uses hierarchical format:
73
+ * Parent:
74
+ * Sublane:
75
+ * code_paths: [...]
76
+ *
77
+ * This function returns the top-level keys (parent names).
78
+ *
79
+ * @param laneInferencePath - Path to .lumenflow.lane-inference.yaml
80
+ * @returns Array of parent names, or empty array if file doesn't exist/is invalid
81
+ */
82
+ export function extractInferenceParents(laneInferencePath) {
83
+ if (!fs.existsSync(laneInferencePath)) {
84
+ return [];
85
+ }
86
+ try {
87
+ const content = fs.readFileSync(laneInferencePath, 'utf-8');
88
+ const parsed = yaml.parse(content);
89
+ if (!parsed || typeof parsed !== 'object') {
90
+ return [];
91
+ }
92
+ // Top-level keys are parent names
93
+ return Object.keys(parsed);
94
+ }
95
+ catch {
96
+ return [];
97
+ }
98
+ }
99
+ /**
100
+ * Extract lane definitions from a workspace YAML file.
101
+ *
102
+ * @param configPath - Path to workspace.yaml
103
+ * @returns Array of lane definitions, or empty array if not found
104
+ */
105
+ export function extractConfigLanes(configPath) {
106
+ if (!fs.existsSync(configPath)) {
107
+ return [];
108
+ }
109
+ try {
110
+ const content = fs.readFileSync(configPath, 'utf-8');
111
+ const parsed = yaml.parse(content);
112
+ if (!parsed || typeof parsed !== 'object') {
113
+ return [];
114
+ }
115
+ const softwareDelivery = parsed[SOFTWARE_DELIVERY_KEY];
116
+ const lanes = softwareDelivery?.lanes;
117
+ const definitions = lanes?.definitions;
118
+ if (!Array.isArray(definitions)) {
119
+ return [];
120
+ }
121
+ return definitions;
122
+ }
123
+ catch {
124
+ return [];
125
+ }
126
+ }
127
+ /**
128
+ * Run lane validation for a project directory.
129
+ *
130
+ * Reads both workspace.yaml and .lumenflow.lane-inference.yaml,
131
+ * then validates that all lane parents exist in the inference hierarchy.
132
+ *
133
+ * @param targetDir - Project root directory
134
+ * @returns Validation result with warnings and invalid lane names
135
+ */
136
+ export function validateLanesForProject(targetDir) {
137
+ const configPath = path.join(targetDir, WORKSPACE_CONFIG_FILE_NAME);
138
+ const inferencePath = path.join(targetDir, '.lumenflow.lane-inference.yaml');
139
+ const configLanes = extractConfigLanes(configPath);
140
+ const inferenceParents = extractInferenceParents(inferencePath);
141
+ // If either file is missing or empty, skip validation
142
+ if (configLanes.length === 0 || inferenceParents.length === 0) {
143
+ return { warnings: [], invalidLanes: [] };
144
+ }
145
+ return validateLaneConfigAgainstInference(configLanes, inferenceParents);
146
+ }
147
+ //# sourceMappingURL=init-lane-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-lane-validation.js","sourceRoot":"","sources":["../src/init-lane-validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ // Copyright (c) 2026 Hellmai Ltd
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * @file init-scaffolding.ts
5
+ * File-system scaffolding helpers for LumenFlow init command (WU-1644)
6
+ *
7
+ * Extracted from init.ts -- file creation, directory creation,
8
+ * template loading/processing, and merge-mode handling.
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as path from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ // WU-1171: Import merge block utilities
14
+ import { updateMergeBlock } from './merge-block.js';
15
+ /**
16
+ * Process template content by replacing placeholders
17
+ */
18
+ export function processTemplate(content, tokens) {
19
+ let output = content;
20
+ for (const [key, value] of Object.entries(tokens)) {
21
+ // eslint-disable-next-line security/detect-non-literal-regexp -- key is from internal token map, not user input
22
+ output = output.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
23
+ }
24
+ return output;
25
+ }
26
+ export function getRelativePath(targetDir, filePath) {
27
+ return path.relative(targetDir, filePath).split(path.sep).join('/');
28
+ }
29
+ /**
30
+ * WU-1171: Get templates directory path
31
+ */
32
+ export function getTemplatesDir() {
33
+ const __filename = fileURLToPath(import.meta.url);
34
+ const __dirname = path.dirname(__filename);
35
+ // Check for dist/templates (production) or ../templates (development)
36
+ const distTemplates = path.join(__dirname, '..', 'templates');
37
+ if (fs.existsSync(distTemplates)) {
38
+ return distTemplates;
39
+ }
40
+ throw new Error(`Templates directory not found at ${distTemplates}`);
41
+ }
42
+ /**
43
+ * WU-1171: Load a template file
44
+ */
45
+ export function loadTemplate(templatePath) {
46
+ const templatesDir = getTemplatesDir();
47
+ const fullPath = path.join(templatesDir, templatePath);
48
+ if (!fs.existsSync(fullPath)) {
49
+ throw new Error(`Template not found: ${templatePath}`);
50
+ }
51
+ return fs.readFileSync(fullPath, 'utf-8');
52
+ }
53
+ /**
54
+ * Convert boolean or FileMode to FileMode
55
+ */
56
+ export function resolveBooleanToFileMode(mode) {
57
+ if (typeof mode === 'boolean') {
58
+ return mode ? 'force' : 'skip';
59
+ }
60
+ return mode;
61
+ }
62
+ /**
63
+ * Handle merge mode file update
64
+ */
65
+ export function handleMergeMode(filePath, content, result, relativePath) {
66
+ const existingContent = fs.readFileSync(filePath, 'utf-8');
67
+ const mergeResult = updateMergeBlock(existingContent, content);
68
+ if (mergeResult.unchanged) {
69
+ result.skipped.push(relativePath);
70
+ return;
71
+ }
72
+ if (mergeResult.warning) {
73
+ result.warnings?.push(`${relativePath}: ${mergeResult.warning}`);
74
+ }
75
+ fs.writeFileSync(filePath, mergeResult.content);
76
+ result.merged?.push(relativePath);
77
+ }
78
+ /**
79
+ * Write a new file, creating parent directories if needed
80
+ */
81
+ export function writeNewFile(filePath, content, result, relativePath) {
82
+ const parentDir = path.dirname(filePath);
83
+ if (!fs.existsSync(parentDir)) {
84
+ fs.mkdirSync(parentDir, { recursive: true });
85
+ }
86
+ fs.writeFileSync(filePath, content);
87
+ result.created.push(relativePath);
88
+ }
89
+ /**
90
+ * Create a directory if missing
91
+ */
92
+ export async function createDirectory(dirPath, result, targetDir) {
93
+ if (!fs.existsSync(dirPath)) {
94
+ fs.mkdirSync(dirPath, { recursive: true });
95
+ result.created.push(getRelativePath(targetDir, dirPath));
96
+ }
97
+ }
98
+ /**
99
+ * WU-1171: Create a file with support for skip, merge, and force modes
100
+ *
101
+ * @param filePath - Path to the file to create
102
+ * @param content - Content to write (or merge block content in merge mode)
103
+ * @param mode - 'skip' (default), 'merge', or 'force'
104
+ * @param result - ScaffoldResult to track created/skipped/merged files
105
+ * @param targetDir - Target directory for relative path calculation
106
+ */
107
+ export async function createFile(filePath, content, mode, result, targetDir) {
108
+ const relativePath = getRelativePath(targetDir, filePath);
109
+ // Handle boolean for backwards compatibility (true = force, false = skip)
110
+ const resolvedMode = resolveBooleanToFileMode(mode);
111
+ // Ensure merged/warnings/overwritten arrays exist
112
+ result.merged = result.merged ?? [];
113
+ result.warnings = result.warnings ?? [];
114
+ result.overwritten = result.overwritten ?? [];
115
+ const fileExists = fs.existsSync(filePath);
116
+ if (fileExists && resolvedMode === 'skip') {
117
+ result.skipped.push(relativePath);
118
+ return;
119
+ }
120
+ if (fileExists && resolvedMode === 'merge') {
121
+ handleMergeMode(filePath, content, result, relativePath);
122
+ return;
123
+ }
124
+ // WU-1965: Track overwritten files when force mode replaces an existing file
125
+ if (fileExists && resolvedMode === 'force') {
126
+ result.overwritten.push(relativePath);
127
+ }
128
+ // Force mode or file doesn't exist: write new content
129
+ writeNewFile(filePath, content, result, relativePath);
130
+ }
131
+ /**
132
+ * WU-1394: Create an executable script file with proper permissions
133
+ * Similar to createFile but sets 0o755 mode for shell scripts
134
+ */
135
+ export async function createExecutableScript(filePath, content, mode, result, targetDir) {
136
+ const relativePath = getRelativePath(targetDir, filePath);
137
+ const resolvedMode = resolveBooleanToFileMode(mode);
138
+ result.merged = result.merged ?? [];
139
+ result.warnings = result.warnings ?? [];
140
+ result.overwritten = result.overwritten ?? [];
141
+ const fileExists = fs.existsSync(filePath);
142
+ if (fileExists && resolvedMode === 'skip') {
143
+ result.skipped.push(relativePath);
144
+ return;
145
+ }
146
+ // WU-1965: Track overwritten files
147
+ if (fileExists && (resolvedMode === 'force' || resolvedMode === 'merge')) {
148
+ result.overwritten.push(relativePath);
149
+ }
150
+ // Write file with executable permissions
151
+ const parentDir = path.dirname(filePath);
152
+ if (!fs.existsSync(parentDir)) {
153
+ fs.mkdirSync(parentDir, { recursive: true });
154
+ }
155
+ fs.writeFileSync(filePath, content, { mode: 0o755 });
156
+ result.created.push(relativePath);
157
+ }
158
+ //# sourceMappingURL=init-scaffolding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init-scaffolding.js","sourceRoot":"","sources":["../src/init-scaffolding.ts"],"names":[],"mappings":"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"}