@lumenflow/cli 3.1.2 → 3.1.3

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 (389) hide show
  1. package/README.md +36 -35
  2. package/dist/agent-issues-query.js +13 -8
  3. package/dist/agent-log-issue.js +15 -4
  4. package/dist/agent-session-end.js +15 -4
  5. package/dist/agent-session.js +18 -6
  6. package/dist/backlog-prune.js +1 -1
  7. package/dist/commands/integrate.js +32 -18
  8. package/dist/config-get.js +27 -15
  9. package/dist/config-set.js +104 -37
  10. package/dist/delegation-list.js +1 -1
  11. package/dist/doctor.js +19 -13
  12. package/dist/file-delete.js +1 -1
  13. package/dist/file-edit.js +1 -1
  14. package/dist/file-read.js +1 -1
  15. package/dist/file-write.js +1 -1
  16. package/dist/flow-bottlenecks.js +1 -1
  17. package/dist/flow-report.js +10 -9
  18. package/dist/gates.js +3 -2
  19. package/dist/git-branch.js +1 -1
  20. package/dist/git-diff.js +1 -1
  21. package/dist/git-log.js +1 -1
  22. package/dist/init.js +238 -42
  23. package/dist/initiative-add-wu.js +1 -1
  24. package/dist/initiative-bulk-assign-wus.js +1 -1
  25. package/dist/initiative-create.js +2 -2
  26. package/dist/initiative-edit.js +1 -1
  27. package/dist/initiative-list.js +1 -1
  28. package/dist/initiative-plan.js +1 -3
  29. package/dist/initiative-status.js +47 -6
  30. package/dist/lane-edit.js +19 -10
  31. package/dist/lane-health.js +13 -24
  32. package/dist/lane-lock.js +4 -5
  33. package/dist/lane-setup.js +5 -5
  34. package/dist/lane-status.js +4 -5
  35. package/dist/lane-suggest.js +9 -7
  36. package/dist/lane-validate.js +4 -5
  37. package/dist/lumenflow-upgrade.js +17 -11
  38. package/dist/mem-checkpoint.js +1 -1
  39. package/dist/mem-cleanup.js +6 -23
  40. package/dist/mem-context.js +1 -1
  41. package/dist/mem-create.js +1 -1
  42. package/dist/mem-delete.js +1 -1
  43. package/dist/mem-export.js +1 -1
  44. package/dist/mem-inbox.js +1 -1
  45. package/dist/mem-init.js +1 -1
  46. package/dist/mem-ready.js +1 -1
  47. package/dist/mem-recover.js +1 -1
  48. package/dist/mem-signal.js +1 -1
  49. package/dist/mem-start.js +1 -1
  50. package/dist/mem-summarize.js +8 -7
  51. package/dist/mem-triage.js +7 -5
  52. package/dist/metrics-cli.js +1 -1
  53. package/dist/metrics-snapshot.js +1 -1
  54. package/dist/onboard.js +295 -120
  55. package/dist/orchestrate-init-status.js +12 -7
  56. package/dist/orchestrate-initiative.js +23 -12
  57. package/dist/orchestrate-monitor.js +20 -8
  58. package/dist/pack-scaffold.js +1 -1
  59. package/dist/plan-create.js +1 -3
  60. package/dist/plan-edit.js +1 -3
  61. package/dist/plan-link.js +1 -3
  62. package/dist/plan-promote.js +1 -3
  63. package/dist/release.js +1 -3
  64. package/dist/signal-cleanup.js +4 -18
  65. package/dist/state-bootstrap.js +11 -8
  66. package/dist/state-cleanup.js +5 -19
  67. package/dist/state-doctor.js +213 -9
  68. package/dist/task-claim.js +1 -1
  69. package/dist/validate.js +1 -1
  70. package/dist/workspace-init.js +61 -61
  71. package/dist/wu-block.js +1 -1
  72. package/dist/wu-brief.js +1 -1
  73. package/dist/wu-claim.js +1 -1
  74. package/dist/wu-cleanup.js +1 -1
  75. package/dist/wu-create.js +3 -3
  76. package/dist/wu-delegate.js +1 -1
  77. package/dist/wu-deps.js +1 -1
  78. package/dist/wu-done.js +66 -34
  79. package/dist/wu-edit.js +1 -1
  80. package/dist/wu-infer-lane.js +1 -1
  81. package/dist/wu-preflight.js +1 -1
  82. package/dist/wu-prep.js +1 -1
  83. package/dist/wu-proto.js +1 -1
  84. package/dist/wu-prune.js +1 -1
  85. package/dist/wu-recover.js +1 -1
  86. package/dist/wu-release.js +1 -1
  87. package/dist/wu-repair.js +1 -1
  88. package/dist/wu-sandbox.js +40 -27
  89. package/dist/wu-status.js +1 -1
  90. package/dist/wu-unblock.js +1 -1
  91. package/dist/wu-unlock-lane.js +1 -1
  92. package/dist/wu-validate.js +1 -1
  93. package/package.json +12 -8
  94. package/packs/software-delivery/constants.ts +10 -0
  95. package/packs/software-delivery/extensions.ts +140 -0
  96. package/packs/software-delivery/gate-policies.ts +134 -0
  97. package/packs/software-delivery/index.ts +8 -0
  98. package/packs/software-delivery/manifest-schema.ts +236 -0
  99. package/packs/software-delivery/manifest.ts +417 -0
  100. package/packs/software-delivery/manifest.yaml +711 -0
  101. package/packs/software-delivery/pack-registration.ts +113 -0
  102. package/packs/software-delivery/tool-impl/agent-tools.ts +263 -0
  103. package/packs/software-delivery/tool-impl/delegation-tools.ts +66 -0
  104. package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +219 -0
  105. package/packs/software-delivery/tool-impl/git-runner.ts +113 -0
  106. package/packs/software-delivery/tool-impl/git-tools.ts +316 -0
  107. package/packs/software-delivery/tool-impl/index.ts +15 -0
  108. package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +720 -0
  109. package/packs/software-delivery/tool-impl/lane-lock.ts +246 -0
  110. package/packs/software-delivery/tool-impl/memory-tools.ts +415 -0
  111. package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +21 -0
  112. package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +328 -0
  113. package/packs/software-delivery/tool-impl/runtime-native-tools.ts +687 -0
  114. package/packs/software-delivery/tool-impl/worker-loader.ts +52 -0
  115. package/packs/software-delivery/tool-impl/worktree-tools.ts +46 -0
  116. package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +759 -0
  117. package/packs/software-delivery/tools/delegation-tools.ts +23 -0
  118. package/packs/software-delivery/tools/git-tools.ts +55 -0
  119. package/packs/software-delivery/tools/index.ts +8 -0
  120. package/packs/software-delivery/tools/lane-lock-tool.ts +37 -0
  121. package/packs/software-delivery/tools/types.ts +71 -0
  122. package/packs/software-delivery/tools/worktree-tools.ts +49 -0
  123. package/templates/core/LUMENFLOW.md.template +3 -3
  124. package/templates/core/ai/onboarding/agent-invocation-guide.md.template +1 -1
  125. package/templates/core/ai/onboarding/lumenflow-force-usage.md.template +1 -1
  126. package/templates/core/ai/onboarding/quick-ref-commands.md.template +5 -5
  127. package/templates/core/ai/onboarding/starting-prompt.md.template +3 -3
  128. package/templates/core/ai/onboarding/vendor-support.md.template +1 -1
  129. package/templates/core/ai/onboarding/wu-create-checklist.md.template +1 -1
  130. package/dist/agent-issues-query.js.map +0 -1
  131. package/dist/agent-log-issue.js.map +0 -1
  132. package/dist/agent-session-end.js.map +0 -1
  133. package/dist/agent-session.js.map +0 -1
  134. package/dist/backlog-prune.js.map +0 -1
  135. package/dist/cli-entry-point.js +0 -149
  136. package/dist/cli-entry-point.js.map +0 -1
  137. package/dist/commands/integrate.js.map +0 -1
  138. package/dist/commands.js.map +0 -1
  139. package/dist/config-get.js.map +0 -1
  140. package/dist/config-set.js.map +0 -1
  141. package/dist/delegation-list.js.map +0 -1
  142. package/dist/deps-add.js +0 -259
  143. package/dist/deps-add.js.map +0 -1
  144. package/dist/deps-remove.js +0 -105
  145. package/dist/deps-remove.js.map +0 -1
  146. package/dist/docs-sync.js.map +0 -1
  147. package/dist/doctor.js.map +0 -1
  148. package/dist/file-delete.js.map +0 -1
  149. package/dist/file-edit.js.map +0 -1
  150. package/dist/file-read.js.map +0 -1
  151. package/dist/file-write.js.map +0 -1
  152. package/dist/flow-bottlenecks.js.map +0 -1
  153. package/dist/flow-report.js.map +0 -1
  154. package/dist/formatters.js +0 -151
  155. package/dist/formatters.js.map +0 -1
  156. package/dist/gate-defaults.js +0 -131
  157. package/dist/gate-defaults.js.map +0 -1
  158. package/dist/gate-registry.js +0 -73
  159. package/dist/gate-registry.js.map +0 -1
  160. package/dist/gates-graceful-degradation.js +0 -153
  161. package/dist/gates-graceful-degradation.js.map +0 -1
  162. package/dist/gates-plan-resolvers.js +0 -152
  163. package/dist/gates-plan-resolvers.js.map +0 -1
  164. package/dist/gates-runners.js +0 -509
  165. package/dist/gates-runners.js.map +0 -1
  166. package/dist/gates-types.js +0 -4
  167. package/dist/gates-types.js.map +0 -1
  168. package/dist/gates-utils.js +0 -323
  169. package/dist/gates-utils.js.map +0 -1
  170. package/dist/gates.js.map +0 -1
  171. package/dist/git-branch.js.map +0 -1
  172. package/dist/git-diff.js.map +0 -1
  173. package/dist/git-log.js.map +0 -1
  174. package/dist/git-status.js.map +0 -1
  175. package/dist/guard-locked.js +0 -172
  176. package/dist/guard-locked.js.map +0 -1
  177. package/dist/guard-main-branch.js +0 -217
  178. package/dist/guard-main-branch.js.map +0 -1
  179. package/dist/guard-worktree-commit.js +0 -163
  180. package/dist/guard-worktree-commit.js.map +0 -1
  181. package/dist/hooks/auto-checkpoint-utils.js +0 -54
  182. package/dist/hooks/auto-checkpoint-utils.js.map +0 -1
  183. package/dist/hooks/enforcement-checks.js +0 -399
  184. package/dist/hooks/enforcement-checks.js.map +0 -1
  185. package/dist/hooks/enforcement-generator.js +0 -139
  186. package/dist/hooks/enforcement-generator.js.map +0 -1
  187. package/dist/hooks/enforcement-sync.js +0 -385
  188. package/dist/hooks/enforcement-sync.js.map +0 -1
  189. package/dist/hooks/generators/auto-checkpoint.js +0 -125
  190. package/dist/hooks/generators/auto-checkpoint.js.map +0 -1
  191. package/dist/hooks/generators/enforce-worktree.js +0 -190
  192. package/dist/hooks/generators/enforce-worktree.js.map +0 -1
  193. package/dist/hooks/generators/index.js +0 -18
  194. package/dist/hooks/generators/index.js.map +0 -1
  195. package/dist/hooks/generators/pre-compact-checkpoint.js +0 -136
  196. package/dist/hooks/generators/pre-compact-checkpoint.js.map +0 -1
  197. package/dist/hooks/generators/require-wu.js +0 -117
  198. package/dist/hooks/generators/require-wu.js.map +0 -1
  199. package/dist/hooks/generators/session-start-recovery.js +0 -103
  200. package/dist/hooks/generators/session-start-recovery.js.map +0 -1
  201. package/dist/hooks/generators/signal-utils.js +0 -54
  202. package/dist/hooks/generators/signal-utils.js.map +0 -1
  203. package/dist/hooks/generators/warn-incomplete.js +0 -67
  204. package/dist/hooks/generators/warn-incomplete.js.map +0 -1
  205. package/dist/hooks/index.js +0 -10
  206. package/dist/hooks/index.js.map +0 -1
  207. package/dist/index.js.map +0 -1
  208. package/dist/init-detection.js +0 -232
  209. package/dist/init-detection.js.map +0 -1
  210. package/dist/init-lane-validation.js +0 -143
  211. package/dist/init-lane-validation.js.map +0 -1
  212. package/dist/init-scaffolding.js +0 -158
  213. package/dist/init-scaffolding.js.map +0 -1
  214. package/dist/init-templates.js +0 -1982
  215. package/dist/init-templates.js.map +0 -1
  216. package/dist/init.js.map +0 -1
  217. package/dist/initiative-add-wu.js.map +0 -1
  218. package/dist/initiative-bulk-assign-wus.js.map +0 -1
  219. package/dist/initiative-create.js.map +0 -1
  220. package/dist/initiative-edit.js.map +0 -1
  221. package/dist/initiative-list.js.map +0 -1
  222. package/dist/initiative-plan.js.map +0 -1
  223. package/dist/initiative-remove-wu.js.map +0 -1
  224. package/dist/initiative-status.js.map +0 -1
  225. package/dist/lane-edit.js.map +0 -1
  226. package/dist/lane-health.js.map +0 -1
  227. package/dist/lane-lifecycle-process.js +0 -366
  228. package/dist/lane-lifecycle-process.js.map +0 -1
  229. package/dist/lane-lock.js.map +0 -1
  230. package/dist/lane-setup.js.map +0 -1
  231. package/dist/lane-status.js.map +0 -1
  232. package/dist/lane-suggest.js.map +0 -1
  233. package/dist/lane-validate.js.map +0 -1
  234. package/dist/lifecycle-regression-harness.js +0 -181
  235. package/dist/lifecycle-regression-harness.js.map +0 -1
  236. package/dist/lumenflow-upgrade.js.map +0 -1
  237. package/dist/mem-checkpoint.js.map +0 -1
  238. package/dist/mem-cleanup.js.map +0 -1
  239. package/dist/mem-context.js.map +0 -1
  240. package/dist/mem-create.js.map +0 -1
  241. package/dist/mem-delete.js.map +0 -1
  242. package/dist/mem-export.js.map +0 -1
  243. package/dist/mem-inbox.js.map +0 -1
  244. package/dist/mem-index.js +0 -214
  245. package/dist/mem-index.js.map +0 -1
  246. package/dist/mem-init.js.map +0 -1
  247. package/dist/mem-profile.js +0 -210
  248. package/dist/mem-profile.js.map +0 -1
  249. package/dist/mem-promote.js +0 -257
  250. package/dist/mem-promote.js.map +0 -1
  251. package/dist/mem-ready.js.map +0 -1
  252. package/dist/mem-recover.js.map +0 -1
  253. package/dist/mem-signal.js.map +0 -1
  254. package/dist/mem-start.js.map +0 -1
  255. package/dist/mem-summarize.js.map +0 -1
  256. package/dist/mem-triage.js.map +0 -1
  257. package/dist/merge-block.js +0 -225
  258. package/dist/merge-block.js.map +0 -1
  259. package/dist/metrics-cli.js.map +0 -1
  260. package/dist/metrics-snapshot.js.map +0 -1
  261. package/dist/onboard.js.map +0 -1
  262. package/dist/onboarding-smoke-test.js +0 -418
  263. package/dist/onboarding-smoke-test.js.map +0 -1
  264. package/dist/orchestrate-init-status.js.map +0 -1
  265. package/dist/orchestrate-initiative.js.map +0 -1
  266. package/dist/orchestrate-monitor.js.map +0 -1
  267. package/dist/pack-author.js.map +0 -1
  268. package/dist/pack-hash.js.map +0 -1
  269. package/dist/pack-install.js.map +0 -1
  270. package/dist/pack-publish.js.map +0 -1
  271. package/dist/pack-scaffold.js.map +0 -1
  272. package/dist/pack-search.js.map +0 -1
  273. package/dist/pack-validate.js.map +0 -1
  274. package/dist/plan-create.js.map +0 -1
  275. package/dist/plan-edit.js.map +0 -1
  276. package/dist/plan-link.js.map +0 -1
  277. package/dist/plan-promote.js.map +0 -1
  278. package/dist/public-manifest.js +0 -920
  279. package/dist/public-manifest.js.map +0 -1
  280. package/dist/release.js.map +0 -1
  281. package/dist/rotate-progress.js +0 -253
  282. package/dist/rotate-progress.js.map +0 -1
  283. package/dist/session-coordinator.js +0 -303
  284. package/dist/session-coordinator.js.map +0 -1
  285. package/dist/shared-validators.js +0 -81
  286. package/dist/shared-validators.js.map +0 -1
  287. package/dist/signal-cleanup.js.map +0 -1
  288. package/dist/state-bootstrap.js.map +0 -1
  289. package/dist/state-cleanup.js.map +0 -1
  290. package/dist/state-doctor-fix.js +0 -226
  291. package/dist/state-doctor-fix.js.map +0 -1
  292. package/dist/state-doctor-stamps.js +0 -23
  293. package/dist/state-doctor-stamps.js.map +0 -1
  294. package/dist/state-doctor.js.map +0 -1
  295. package/dist/strict-progress.js +0 -255
  296. package/dist/strict-progress.js.map +0 -1
  297. package/dist/sync-templates.js.map +0 -1
  298. package/dist/task-claim.js.map +0 -1
  299. package/dist/trace-gen.js +0 -401
  300. package/dist/trace-gen.js.map +0 -1
  301. package/dist/validate-agent-skills.js +0 -223
  302. package/dist/validate-agent-skills.js.map +0 -1
  303. package/dist/validate-agent-sync.js +0 -151
  304. package/dist/validate-agent-sync.js.map +0 -1
  305. package/dist/validate-backlog-sync.js +0 -77
  306. package/dist/validate-backlog-sync.js.map +0 -1
  307. package/dist/validate-skills-spec.js +0 -211
  308. package/dist/validate-skills-spec.js.map +0 -1
  309. package/dist/validate.js.map +0 -1
  310. package/dist/validator-defaults.js +0 -107
  311. package/dist/validator-defaults.js.map +0 -1
  312. package/dist/validator-registry.js +0 -71
  313. package/dist/validator-registry.js.map +0 -1
  314. package/dist/workspace-init.js.map +0 -1
  315. package/dist/wu-block.js.map +0 -1
  316. package/dist/wu-brief.js.map +0 -1
  317. package/dist/wu-claim-branch.js +0 -123
  318. package/dist/wu-claim-branch.js.map +0 -1
  319. package/dist/wu-claim-cloud.js +0 -79
  320. package/dist/wu-claim-cloud.js.map +0 -1
  321. package/dist/wu-claim-mode.js +0 -82
  322. package/dist/wu-claim-mode.js.map +0 -1
  323. package/dist/wu-claim-output.js +0 -85
  324. package/dist/wu-claim-output.js.map +0 -1
  325. package/dist/wu-claim-repair-guidance.js +0 -12
  326. package/dist/wu-claim-repair-guidance.js.map +0 -1
  327. package/dist/wu-claim-resume-handler.js +0 -87
  328. package/dist/wu-claim-resume-handler.js.map +0 -1
  329. package/dist/wu-claim-state.js +0 -581
  330. package/dist/wu-claim-state.js.map +0 -1
  331. package/dist/wu-claim-validation.js +0 -457
  332. package/dist/wu-claim-validation.js.map +0 -1
  333. package/dist/wu-claim-worktree.js +0 -223
  334. package/dist/wu-claim-worktree.js.map +0 -1
  335. package/dist/wu-claim.js.map +0 -1
  336. package/dist/wu-cleanup-cloud.js +0 -78
  337. package/dist/wu-cleanup-cloud.js.map +0 -1
  338. package/dist/wu-cleanup.js.map +0 -1
  339. package/dist/wu-code-path-coverage.js +0 -83
  340. package/dist/wu-code-path-coverage.js.map +0 -1
  341. package/dist/wu-create-cloud.js +0 -30
  342. package/dist/wu-create-cloud.js.map +0 -1
  343. package/dist/wu-create-content.js +0 -264
  344. package/dist/wu-create-content.js.map +0 -1
  345. package/dist/wu-create-readiness.js +0 -59
  346. package/dist/wu-create-readiness.js.map +0 -1
  347. package/dist/wu-create-validation.js +0 -128
  348. package/dist/wu-create-validation.js.map +0 -1
  349. package/dist/wu-create.js.map +0 -1
  350. package/dist/wu-delegate.js.map +0 -1
  351. package/dist/wu-delete.js.map +0 -1
  352. package/dist/wu-deps.js.map +0 -1
  353. package/dist/wu-done-auto-cleanup.js +0 -203
  354. package/dist/wu-done-auto-cleanup.js.map +0 -1
  355. package/dist/wu-done-check.js +0 -38
  356. package/dist/wu-done-check.js.map +0 -1
  357. package/dist/wu-done-cloud.js +0 -48
  358. package/dist/wu-done-cloud.js.map +0 -1
  359. package/dist/wu-done-decay.js +0 -86
  360. package/dist/wu-done-decay.js.map +0 -1
  361. package/dist/wu-done.js.map +0 -1
  362. package/dist/wu-edit-operations.js +0 -399
  363. package/dist/wu-edit-operations.js.map +0 -1
  364. package/dist/wu-edit-validators.js +0 -282
  365. package/dist/wu-edit-validators.js.map +0 -1
  366. package/dist/wu-edit.js.map +0 -1
  367. package/dist/wu-infer-lane.js.map +0 -1
  368. package/dist/wu-preflight.js.map +0 -1
  369. package/dist/wu-prep.js.map +0 -1
  370. package/dist/wu-proto.js.map +0 -1
  371. package/dist/wu-prune.js.map +0 -1
  372. package/dist/wu-recover.js.map +0 -1
  373. package/dist/wu-release.js.map +0 -1
  374. package/dist/wu-repair.js.map +0 -1
  375. package/dist/wu-sandbox.js.map +0 -1
  376. package/dist/wu-spawn-completion.js +0 -33
  377. package/dist/wu-spawn-completion.js.map +0 -1
  378. package/dist/wu-spawn-prompt-builders.js +0 -1197
  379. package/dist/wu-spawn-prompt-builders.js.map +0 -1
  380. package/dist/wu-spawn-strategy-resolver.js +0 -322
  381. package/dist/wu-spawn-strategy-resolver.js.map +0 -1
  382. package/dist/wu-spawn.js +0 -59
  383. package/dist/wu-spawn.js.map +0 -1
  384. package/dist/wu-state-cloud.js +0 -41
  385. package/dist/wu-state-cloud.js.map +0 -1
  386. package/dist/wu-status.js.map +0 -1
  387. package/dist/wu-unblock.js.map +0 -1
  388. package/dist/wu-unlock-lane.js.map +0 -1
  389. package/dist/wu-validate.js.map +0 -1
package/dist/init.js CHANGED
@@ -19,6 +19,7 @@ import * as path from 'node:path';
19
19
  import * as yaml from 'yaml';
20
20
  import { execFileSync } from 'node:child_process';
21
21
  import { getDefaultConfig, createWUParser, WU_OPTIONS, CLAUDE_HOOKS, LUMENFLOW_CLIENT_IDS, } from '@lumenflow/core';
22
+ import { WORKSPACE_V2_KEYS } from '@lumenflow/core/config-schema';
22
23
  // WU-1067: Import GATE_PRESETS for --preset support
23
24
  import { GATE_PRESETS } from '@lumenflow/core/gates-config';
24
25
  // WU-1362: Import worktree guard utilities for branch checking
@@ -41,6 +42,7 @@ import { getDocsPath, detectDocsStructure, detectDefaultClient, isGitRepo, hasGi
41
42
  export { detectIDEEnvironment, checkPrerequisites, getDocsPath, detectDocsStructure, } from './init-detection.js';
42
43
  // WU-1644: Import scaffolding helpers from dedicated module
43
44
  import { processTemplate, loadTemplate, createFile, createDirectory, createExecutableScript, } from './init-scaffolding.js';
45
+ import { CANONICAL_BOOTSTRAP_COMMAND, DEFAULT_PROJECT_NAME, getDefaultWorkspaceConfig, WORKSPACE_FILENAME, } from './workspace-init.js';
44
46
  /**
45
47
  * WU-1085: CLI option definitions for init command
46
48
  * WU-1171: Added --merge and --client options
@@ -84,8 +86,33 @@ const INIT_OPTIONS = {
84
86
  flags: '--preset <preset>',
85
87
  description: 'Gate preset for config (node, python, go, rust, dotnet)',
86
88
  },
89
+ bootstrapDomain: {
90
+ name: 'bootstrapDomain',
91
+ flags: '--bootstrap-domain <domain>',
92
+ description: 'Bootstrap domain: software-delivery, infra, or custom',
93
+ },
94
+ skipBootstrap: {
95
+ name: 'skipBootstrap',
96
+ flags: '--skip-bootstrap',
97
+ description: 'Skip workspace bootstrap-all flow (workspace.yaml + pack install)',
98
+ },
99
+ skipBootstrapPackInstall: {
100
+ name: 'skipBootstrapPackInstall',
101
+ flags: '--skip-bootstrap-pack-install',
102
+ description: 'Skip registry pack install during bootstrap',
103
+ },
87
104
  force: WU_OPTIONS.force,
88
105
  };
106
+ function parseBootstrapDomain(rawDomain) {
107
+ if (!rawDomain) {
108
+ return BOOTSTRAP_DEFAULT_DOMAIN;
109
+ }
110
+ if (BOOTSTRAP_VALID_DOMAINS.has(rawDomain)) {
111
+ return rawDomain;
112
+ }
113
+ const validDomains = Array.from(BOOTSTRAP_VALID_DOMAINS).join(', ');
114
+ throw new Error(`${BOOTSTRAP_ERROR_PREFIX} Invalid --bootstrap-domain "${rawDomain}". Valid values: ${validDomains}`);
115
+ }
89
116
  /**
90
117
  * WU-1085: Parse init command options using createWUParser
91
118
  * WU-1171: Added --merge, --client options
@@ -97,7 +124,8 @@ export function parseInitOptions() {
97
124
  name: 'lumenflow-init',
98
125
  description: 'Initialize LumenFlow in a project\n\n' +
99
126
  'Subcommands:\n' +
100
- ' lumenflow commands List all available CLI commands',
127
+ ' lumenflow commands List all available CLI commands\n' +
128
+ ' lumenflow cloud connect Configure cloud control-plane access',
101
129
  options: Object.values(INIT_OPTIONS),
102
130
  });
103
131
  // WU-1171: --client takes precedence, --vendor is alias
@@ -105,6 +133,7 @@ export function parseInitOptions() {
105
133
  // WU-1286: --full is now the default (true), use --minimal to disable
106
134
  // --minimal explicitly sets full to false, otherwise full defaults to true
107
135
  const fullMode = opts.minimal ? false : (opts.full ?? true);
136
+ const bootstrapDomain = parseBootstrapDomain(opts.bootstrapDomain);
108
137
  return {
109
138
  force: opts.force ?? false,
110
139
  full: fullMode,
@@ -113,10 +142,48 @@ export function parseInitOptions() {
113
142
  client: clientValue,
114
143
  vendor: clientValue,
115
144
  preset: opts.preset,
145
+ bootstrapDomain,
146
+ skipBootstrap: Boolean(opts.skipBootstrap),
147
+ skipBootstrapPackInstall: Boolean(opts.skipBootstrapPackInstall),
116
148
  };
117
149
  }
118
150
  const DEFAULT_CLIENT_CLAUDE = LUMENFLOW_CLIENT_IDS.CLAUDE_CODE;
119
- const CONFIG_FILE_NAME = '.lumenflow.config.yaml';
151
+ const BOOTSTRAP_DEFAULT_DOMAIN = 'software-delivery';
152
+ const BOOTSTRAP_INFRA_DOMAIN = 'infra';
153
+ const BOOTSTRAP_CUSTOM_DOMAIN = 'custom';
154
+ const BOOTSTRAP_VALID_DOMAINS = new Set([
155
+ BOOTSTRAP_DEFAULT_DOMAIN,
156
+ BOOTSTRAP_INFRA_DOMAIN,
157
+ BOOTSTRAP_CUSTOM_DOMAIN,
158
+ ]);
159
+ const BOOTSTRAP_SKIP_REASON_FLAG = '--skip-bootstrap';
160
+ const BOOTSTRAP_SKIP_REASON_EXISTING_WORKSPACE = `${WORKSPACE_FILENAME} already exists`;
161
+ const BOOTSTRAP_ERROR_PREFIX = '[lumenflow bootstrap]';
162
+ const INIT_SUBCOMMANDS = {
163
+ COMMANDS: 'commands',
164
+ CLOUD: 'cloud',
165
+ };
166
+ const LEGACY_SUBCOMMANDS = {
167
+ ONBOARD: 'onboard',
168
+ WORKSPACE_INIT_COLON: 'workspace:init',
169
+ WORKSPACE_INIT_DASH: 'workspace-init',
170
+ };
171
+ const CLOUD_SUBCOMMANDS = {
172
+ CONNECT: 'connect',
173
+ };
174
+ const CLOUD_CONNECT_BIN = 'cloud-connect';
175
+ const INIT_ERROR_PREFIX = '[lumenflow init]';
176
+ const INIT_CLOUD_CONNECT_HELP = 'Usage: lumenflow cloud connect --endpoint <url> --org-id <id> --project-id <id> [--token-env <name>]';
177
+ const LEGACY_SUBCOMMAND_ERROR_PREFIX = `${INIT_ERROR_PREFIX} Legacy onboarding subcommand`;
178
+ const LEGACY_SUBCOMMAND_GUIDANCE = `Use "${CANONICAL_BOOTSTRAP_COMMAND}" for bootstrap-all onboarding`;
179
+ const LEGACY_SUBCOMMAND_HELP_HINT = `Run "${CANONICAL_BOOTSTRAP_COMMAND} --help" for supported options`;
180
+ const CONFIG_FILE_NAME = WORKSPACE_FILENAME;
181
+ const SOFTWARE_DELIVERY_KEY = WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY;
182
+ const SOFTWARE_DELIVERY_CONFIG_KEYS = {
183
+ AGENTS: 'agents',
184
+ CLIENTS: 'clients',
185
+ ENFORCEMENT: 'enforcement',
186
+ };
120
187
  const FRAMEWORK_HINT_FILE = '.lumenflow.framework.yaml';
121
188
  const LUMENFLOW_DIR = '.lumenflow';
122
189
  const LUMENFLOW_AGENTS_DIR = `${LUMENFLOW_DIR}/agents`;
@@ -210,30 +277,77 @@ function detectProjectTooling(targetDir) {
210
277
  return { hasTurbo: false };
211
278
  }
212
279
  }
280
+ function asRecord(value) {
281
+ return value && typeof value === 'object' && !Array.isArray(value)
282
+ ? value
283
+ : null;
284
+ }
285
+ function mergeConfigDefaults(defaults, existing) {
286
+ const merged = { ...defaults };
287
+ for (const [key, existingValue] of Object.entries(existing)) {
288
+ const defaultValue = merged[key];
289
+ const existingRecord = asRecord(existingValue);
290
+ const defaultRecord = asRecord(defaultValue);
291
+ if (defaultRecord && existingRecord) {
292
+ merged[key] = mergeConfigDefaults(defaultRecord, existingRecord);
293
+ continue;
294
+ }
295
+ merged[key] = existingValue;
296
+ }
297
+ return merged;
298
+ }
299
+ function toWorkspaceId(value) {
300
+ return value
301
+ .toLowerCase()
302
+ .replace(/[^a-z0-9]+/g, '-')
303
+ .replace(/^-+|-+$/g, '');
304
+ }
305
+ function loadWorkspaceDocument(targetDir) {
306
+ const workspacePath = path.join(targetDir, CONFIG_FILE_NAME);
307
+ if (!fs.existsSync(workspacePath)) {
308
+ const projectName = resolveBootstrapProjectName(targetDir);
309
+ const projectId = toWorkspaceId(projectName);
310
+ const workspace = {
311
+ ...getDefaultWorkspaceConfig(),
312
+ id: projectId,
313
+ name: projectName,
314
+ memory_namespace: projectId,
315
+ event_namespace: projectId,
316
+ };
317
+ return { exists: false, workspace };
318
+ }
319
+ const content = fs.readFileSync(workspacePath, 'utf-8');
320
+ const workspace = asRecord(yaml.parse(content));
321
+ if (!workspace) {
322
+ throw new Error(`${INIT_ERROR_PREFIX} ${CONFIG_FILE_NAME} exists but is not a valid YAML object. ` +
323
+ `Fix ${CONFIG_FILE_NAME} and re-run init.`);
324
+ }
325
+ return { exists: true, workspace };
326
+ }
327
+ function upsertWorkspaceSoftwareDelivery(targetDir, softwareDeliveryConfig, result) {
328
+ const workspacePath = path.join(targetDir, CONFIG_FILE_NAME);
329
+ const { exists, workspace } = loadWorkspaceDocument(targetDir);
330
+ const existingSoftwareDelivery = asRecord(workspace[SOFTWARE_DELIVERY_KEY]) ?? {};
331
+ workspace[SOFTWARE_DELIVERY_KEY] = mergeConfigDefaults(softwareDeliveryConfig, existingSoftwareDelivery);
332
+ fs.writeFileSync(workspacePath, yaml.stringify(workspace), 'utf-8');
333
+ if (exists) {
334
+ result.overwritten = result.overwritten ?? [];
335
+ if (!result.overwritten.includes(CONFIG_FILE_NAME)) {
336
+ result.overwritten.push(CONFIG_FILE_NAME);
337
+ }
338
+ return;
339
+ }
340
+ result.created.push(CONFIG_FILE_NAME);
341
+ }
213
342
  /**
214
- * Generate YAML configuration with header comment
343
+ * Build software_delivery configuration defaults
215
344
  * WU-1067: Supports --preset option for config-driven gates
216
345
  * WU-1307: Includes default lane definitions for onboarding
217
346
  * WU-1364: Supports git config overrides (requireRemote)
218
347
  * WU-1383: Adds enforcement hooks config for Claude client by default
219
348
  * WU-1965: Detects installed tooling from package.json for config defaults
220
349
  */
221
- function generateLumenflowConfigYaml(gatePreset, gitConfigOverride, client, docsPaths, targetDir) {
222
- // WU-1382: Add managed file header to prevent manual edits
223
- const header = `# ============================================================================
224
- # LUMENFLOW MANAGED FILE - DO NOT EDIT MANUALLY
225
- # ============================================================================
226
- # Generated by: lumenflow init
227
- # Regenerate with: pnpm exec lumenflow init --force
228
- #
229
- # This file is managed by LumenFlow tooling. Manual edits may be overwritten.
230
- # To customize, use the CLI commands or edit the appropriate source templates.
231
- # ============================================================================
232
-
233
- # LumenFlow Configuration
234
- # Customize paths based on your project structure
235
-
236
- `;
350
+ function buildSoftwareDeliveryConfig(gatePreset, gitConfigOverride, client, docsPaths, targetDir) {
237
351
  const config = getDefaultConfig();
238
352
  config.directories.agentsDir = LUMENFLOW_AGENTS_DIR;
239
353
  // WU-1755: Override directory paths to match detected docs structure.
@@ -319,7 +433,7 @@ function generateLumenflowConfigYaml(gatePreset, gitConfigOverride, client, docs
319
433
  },
320
434
  };
321
435
  }
322
- return header + yaml.stringify(config);
436
+ return config;
323
437
  }
324
438
  /**
325
439
  * Get current date in YYYY-MM-DD format
@@ -381,22 +495,29 @@ async function runClientIntegrations(targetDir, result) {
381
495
  const configPath = path.join(targetDir, CONFIG_FILE_NAME);
382
496
  if (!fs.existsSync(configPath))
383
497
  return integrationFiles;
384
- let config;
498
+ let softwareDeliveryConfig;
385
499
  try {
386
500
  const content = fs.readFileSync(configPath, 'utf-8');
387
- config = yaml.parse(content);
501
+ const workspaceConfig = asRecord(yaml.parse(content));
502
+ softwareDeliveryConfig = workspaceConfig
503
+ ? asRecord(workspaceConfig[SOFTWARE_DELIVERY_KEY])
504
+ : null;
388
505
  }
389
506
  catch {
390
507
  return integrationFiles; // Config unreadable -- skip silently
391
508
  }
392
- if (!config)
509
+ if (!softwareDeliveryConfig)
393
510
  return integrationFiles;
394
- const agents = config.agents;
395
- const clients = agents?.clients;
511
+ const agents = asRecord(softwareDeliveryConfig[SOFTWARE_DELIVERY_CONFIG_KEYS.AGENTS]);
512
+ const clients = asRecord(agents?.[SOFTWARE_DELIVERY_CONFIG_KEYS.CLIENTS]);
396
513
  if (!clients)
397
514
  return integrationFiles;
398
- for (const [clientKey, clientConfig] of Object.entries(clients)) {
399
- const enforcement = clientConfig.enforcement;
515
+ for (const [clientKey, unsafeClientConfig] of Object.entries(clients)) {
516
+ const clientConfig = asRecord(unsafeClientConfig);
517
+ if (!clientConfig) {
518
+ continue;
519
+ }
520
+ const enforcement = asRecord(clientConfig[SOFTWARE_DELIVERY_CONFIG_KEYS.ENFORCEMENT]);
400
521
  if (!enforcement?.hooks)
401
522
  continue;
402
523
  const integration = CLIENT_INTEGRATIONS[clientKey];
@@ -504,19 +625,8 @@ export async function scaffoldProject(targetDir, options) {
504
625
  DOCS_TASKS_PATH: docsPaths.tasks,
505
626
  DOCS_ONBOARDING_PATH: docsPaths.onboarding,
506
627
  };
507
- // Create .lumenflow.config.yaml (WU-1067: includes gate preset if specified)
508
- // WU-1364: Includes git config overrides (e.g., requireRemote: false for local-only)
509
- // WU-1383: Includes enforcement hooks for Claude client
510
- // Note: Config files don't use merge mode (always skip or force)
511
- const configPath = path.join(targetDir, CONFIG_FILE_NAME);
512
- // WU-1383: Warn if config already exists to discourage manual editing
513
- if (fs.existsSync(configPath) && !options.force) {
514
- result.warnings = result.warnings ?? [];
515
- result.warnings.push(`${CONFIG_FILE_NAME} already exists. ` +
516
- 'To modify configuration, use CLI commands (e.g., pnpm lumenflow:init --force) ' +
517
- 'instead of manual editing.');
518
- }
519
- await createFile(configPath, generateLumenflowConfigYaml(options.gatePreset, gitConfigOverride, client, docsPaths, targetDir), options.force ? 'force' : 'skip', result, targetDir);
628
+ // Upsert workspace.yaml software_delivery defaults (WU-2006 hard cut)
629
+ upsertWorkspaceSoftwareDelivery(targetDir, buildSoftwareDeliveryConfig(options.gatePreset, gitConfigOverride, client, docsPaths, targetDir), result);
520
630
  // WU-1171: Create AGENTS.md (universal entry point for all agents)
521
631
  try {
522
632
  const agentsTemplate = loadTemplate('core/AGENTS.md.template');
@@ -964,6 +1074,56 @@ async function scaffoldClientFiles(targetDir, options, result, tokens, client) {
964
1074
  await createFile(path.join(targetDir, '.aider.conf.yml'), AIDER_CONF_TEMPLATE, fileMode, result, targetDir);
965
1075
  }
966
1076
  }
1077
+ function resolveBootstrapProjectName(targetDir) {
1078
+ const basename = path.basename(path.resolve(targetDir)).trim();
1079
+ return basename.length > 0 ? basename : DEFAULT_PROJECT_NAME;
1080
+ }
1081
+ export async function runInitBootstrap(options) {
1082
+ if (options.skipBootstrap) {
1083
+ return {
1084
+ skipped: true,
1085
+ reason: BOOTSTRAP_SKIP_REASON_FLAG,
1086
+ workspaceGenerated: false,
1087
+ packInstalled: false,
1088
+ };
1089
+ }
1090
+ const workspacePath = path.join(options.targetDir, WORKSPACE_FILENAME);
1091
+ const hasExistingWorkspace = fs.existsSync(workspacePath);
1092
+ if (hasExistingWorkspace && !options.force) {
1093
+ return {
1094
+ skipped: true,
1095
+ reason: BOOTSTRAP_SKIP_REASON_EXISTING_WORKSPACE,
1096
+ workspaceGenerated: false,
1097
+ packInstalled: false,
1098
+ };
1099
+ }
1100
+ const onboardModule = await import('./onboard.js');
1101
+ const onboardResult = (await onboardModule.runOnboard({
1102
+ targetDir: options.targetDir,
1103
+ nonInteractive: true,
1104
+ projectName: resolveBootstrapProjectName(options.targetDir),
1105
+ domain: options.bootstrapDomain,
1106
+ force: options.force,
1107
+ skipPackInstall: options.skipBootstrapPackInstall,
1108
+ skipDashboard: true,
1109
+ fetchFn: options.fetchFn ?? globalThis.fetch,
1110
+ }));
1111
+ if (!onboardResult.success) {
1112
+ const failureReason = onboardResult.errors.join('; ') || 'unknown onboarding error';
1113
+ throw new Error(`${BOOTSTRAP_ERROR_PREFIX} ${failureReason}`);
1114
+ }
1115
+ if (!options.skipBootstrapPackInstall &&
1116
+ options.bootstrapDomain !== BOOTSTRAP_CUSTOM_DOMAIN &&
1117
+ onboardResult.packInstalled !== true) {
1118
+ throw new Error(`${BOOTSTRAP_ERROR_PREFIX} failed to install ${options.bootstrapDomain} pack with integrity metadata. ` +
1119
+ `Retry after fixing registry access or rerun with --skip-bootstrap-pack-install.`);
1120
+ }
1121
+ return {
1122
+ skipped: false,
1123
+ workspaceGenerated: onboardResult.workspaceGenerated === true,
1124
+ packInstalled: onboardResult.packInstalled === true,
1125
+ };
1126
+ }
967
1127
  /**
968
1128
  * CLI entry point
969
1129
  * WU-1085: Updated to use parseInitOptions for proper --help support
@@ -972,8 +1132,14 @@ async function scaffoldClientFiles(targetDir, options, result, tokens, client) {
972
1132
  */
973
1133
  export async function main() {
974
1134
  // WU-1378: Check for subcommands before parsing init options
1135
+ const invokedBinary = path.basename(process.argv[1] ?? '', '.js');
975
1136
  const subcommand = process.argv[2];
976
- if (subcommand === 'commands') {
1137
+ if (invokedBinary === CLOUD_CONNECT_BIN) {
1138
+ const { runCloudConnectCli } = await import('./onboard.js');
1139
+ await runCloudConnectCli();
1140
+ return;
1141
+ }
1142
+ if (subcommand === INIT_SUBCOMMANDS.COMMANDS) {
977
1143
  // Route to commands subcommand
978
1144
  const { main: commandsMain } = await import('./commands.js');
979
1145
  // Remove 'commands' from argv so the subcommand parser sees clean args
@@ -981,6 +1147,21 @@ export async function main() {
981
1147
  await commandsMain();
982
1148
  return;
983
1149
  }
1150
+ if (subcommand === LEGACY_SUBCOMMANDS.ONBOARD ||
1151
+ subcommand === LEGACY_SUBCOMMANDS.WORKSPACE_INIT_COLON ||
1152
+ subcommand === LEGACY_SUBCOMMANDS.WORKSPACE_INIT_DASH) {
1153
+ throw new Error(`${LEGACY_SUBCOMMAND_ERROR_PREFIX} "${subcommand}". ${LEGACY_SUBCOMMAND_GUIDANCE}. ${LEGACY_SUBCOMMAND_HELP_HINT}.`);
1154
+ }
1155
+ if (subcommand === INIT_SUBCOMMANDS.CLOUD) {
1156
+ const cloudSubcommand = process.argv[3];
1157
+ if (cloudSubcommand !== CLOUD_SUBCOMMANDS.CONNECT) {
1158
+ throw new Error(`${INIT_ERROR_PREFIX} Unknown cloud subcommand "${cloudSubcommand ?? ''}". ${INIT_CLOUD_CONNECT_HELP}`);
1159
+ }
1160
+ const { runCloudConnectCli } = await import('./onboard.js');
1161
+ process.argv.splice(2, 2);
1162
+ await runCloudConnectCli();
1163
+ return;
1164
+ }
984
1165
  const opts = parseInitOptions();
985
1166
  const targetDir = process.cwd();
986
1167
  console.log('[lumenflow init] Scaffolding LumenFlow project...');
@@ -988,9 +1169,24 @@ export async function main() {
988
1169
  console.log(` Framework: ${opts.framework ?? 'none'}`);
989
1170
  console.log(` Client: ${opts.client ?? 'auto'}`);
990
1171
  console.log(` Gate preset: ${opts.preset ?? 'none (manual config)'}`);
1172
+ console.log(` Bootstrap domain: ${opts.bootstrapDomain}`);
1173
+ console.log(` Bootstrap pack install: ${opts.skipBootstrapPackInstall ? 'skipped (--skip-bootstrap-pack-install)' : 'required'}`);
991
1174
  // WU-1968: Removed separate checkPrerequisites() call here.
992
1175
  // runDoctorForInit() (called after scaffolding) already checks prerequisites
993
1176
  // and displays results, avoiding duplicate output.
1177
+ const bootstrapResult = await runInitBootstrap({
1178
+ targetDir,
1179
+ force: opts.force,
1180
+ bootstrapDomain: opts.bootstrapDomain,
1181
+ skipBootstrap: opts.skipBootstrap,
1182
+ skipBootstrapPackInstall: opts.skipBootstrapPackInstall,
1183
+ });
1184
+ if (bootstrapResult.skipped) {
1185
+ console.log(` Bootstrap: skipped (${bootstrapResult.reason})`);
1186
+ }
1187
+ else {
1188
+ console.log(` Bootstrap: workspace=${bootstrapResult.workspaceGenerated ? 'created' : 'unchanged'}, pack=${bootstrapResult.packInstalled ? 'installed' : 'skipped'}`);
1189
+ }
994
1190
  const result = await scaffoldProject(targetDir, {
995
1191
  force: opts.force,
996
1192
  full: opts.full,
@@ -1038,7 +1234,7 @@ export async function main() {
1038
1234
  // WU-1576: Show enforcement hooks status -- vendor-agnostic (UnsafeAny adapter that produced files)
1039
1235
  console.log('\n[lumenflow init] Done! Next steps:');
1040
1236
  console.log(' 1. Review AGENTS.md and LUMENFLOW.md for workflow documentation');
1041
- console.log(` 2. Edit ${CONFIG_FILE_NAME} to match your project structure`);
1237
+ console.log(` 2. Review ${CONFIG_FILE_NAME} ${SOFTWARE_DELIVERY_KEY} settings for project defaults`);
1042
1238
  console.log('');
1043
1239
  console.log(` ${buildInitLaneLifecycleMessage(LANE_LIFECYCLE_STATUS.UNCONFIGURED)}`);
1044
1240
  if (result.integrationFiles && result.integrationFiles.length > 0) {
@@ -384,7 +384,7 @@ export function buildAddWuMicroWorktreeOptions(wuArg, initId) {
384
384
  },
385
385
  };
386
386
  }
387
- async function main() {
387
+ export async function main() {
388
388
  const args = createWUParser({
389
389
  name: 'initiative-add-wu',
390
390
  description: 'Link one or more WUs to an initiative bidirectionally',
@@ -242,7 +242,7 @@ function printSummary(stats) {
242
242
  /**
243
243
  * Main function
244
244
  */
245
- async function main() {
245
+ export async function main() {
246
246
  const args = createWUParser({
247
247
  name: 'initiative-bulk-assign-wus',
248
248
  description: 'Bulk-assign orphaned WUs to initiatives based on lane prefix rules',
@@ -117,14 +117,14 @@ function createInitiativeYamlInWorktree(worktreePath, id, slug, title, options =
117
117
  }
118
118
  /**
119
119
  * Resolve lane lifecycle classification for initiative:create without mutating
120
- * .lumenflow.config.yaml.
120
+ * workspace.yaml.
121
121
  *
122
122
  * WU-1751: initiative:create guidance should be read-only.
123
123
  */
124
124
  export function resolveLaneLifecycleForInitiativeCreate(projectRoot) {
125
125
  return ensureLaneLifecycleForProject(projectRoot, { persist: false });
126
126
  }
127
- async function main() {
127
+ export async function main() {
128
128
  const args = createWUParser({
129
129
  name: 'initiative-create',
130
130
  description: 'Create a new Initiative with micro-worktree isolation (race-safe)',
@@ -469,7 +469,7 @@ export function buildNoEditsMessage() {
469
469
  /**
470
470
  * Main entry point
471
471
  */
472
- async function main() {
472
+ export async function main() {
473
473
  const opts = parseArgs();
474
474
  const { id } = opts;
475
475
  console.log(`${PREFIX} Starting Initiative edit for ${id}`);
@@ -73,7 +73,7 @@ function truncate(str, maxLen) {
73
73
  return '';
74
74
  return str.length > maxLen ? `${str.substring(0, maxLen - 3)}...` : str;
75
75
  }
76
- async function main() {
76
+ export async function main() {
77
77
  const args = createWUParser({
78
78
  name: 'initiative-list',
79
79
  description: 'List all initiatives with progress percentages',
@@ -252,7 +252,7 @@ export function getCommitMessage(initId, planUri) {
252
252
  const filename = planUri.replace(PLAN_URI_SCHEME, '');
253
253
  return `docs: link plan ${filename} to ${initId.toLowerCase()}`;
254
254
  }
255
- async function main() {
255
+ export async function main() {
256
256
  const args = createWUParser({
257
257
  name: 'init-plan',
258
258
  description: 'Link a plan file to an initiative',
@@ -377,6 +377,4 @@ import { runCLI } from './cli-entry-point.js';
377
377
  if (import.meta.main) {
378
378
  void runCLI(main);
379
379
  }
380
- // Export for testing
381
- export { main };
382
380
  //# sourceMappingURL=initiative-plan.js.map
@@ -40,11 +40,29 @@ function hasIncompletePhase(phases) {
40
40
  return normalizeLifecycleStatus(phase.status) !== WU_STATUS.DONE;
41
41
  });
42
42
  }
43
- export function deriveInitiativeLifecycleStatus(status, phases) {
43
+ function hasAllLinkedWUsDone(progress) {
44
+ if (!progress) {
45
+ return false;
46
+ }
47
+ return progress.total > 0 && progress.done === progress.total;
48
+ }
49
+ function hasIncompleteLinkedWUs(progress) {
50
+ if (!progress) {
51
+ return false;
52
+ }
53
+ return progress.total > 0 && progress.done < progress.total;
54
+ }
55
+ export function deriveInitiativeLifecycleStatus(status, phases, progress) {
44
56
  const normalizedStatus = normalizeLifecycleStatus(status);
57
+ if (hasAllLinkedWUsDone(progress)) {
58
+ return WU_STATUS.DONE;
59
+ }
45
60
  if (normalizedStatus === WU_STATUS.DONE && hasIncompletePhase(phases)) {
46
61
  return WU_STATUS.IN_PROGRESS;
47
62
  }
63
+ if (normalizedStatus === WU_STATUS.DONE && hasIncompleteLinkedWUs(progress)) {
64
+ return WU_STATUS.IN_PROGRESS;
65
+ }
48
66
  return normalizedStatus || WU_STATUS.IN_PROGRESS;
49
67
  }
50
68
  function getWUBlockers(doc) {
@@ -54,6 +72,28 @@ function getWUBlockers(doc) {
54
72
  }
55
73
  return asStringArray(doc.dependencies);
56
74
  }
75
+ function hasPhaseWUStatus(phaseWUs, status) {
76
+ return phaseWUs.some((wu) => normalizeLifecycleStatus(wu.doc.status) === status);
77
+ }
78
+ function areAllPhaseWUsDone(phaseWUs) {
79
+ return (phaseWUs.length > 0 &&
80
+ phaseWUs.every((wu) => normalizeLifecycleStatus(wu.doc.status) === WU_STATUS.DONE));
81
+ }
82
+ export function deriveInitiativePhaseStatus(status, phaseWUs) {
83
+ if (areAllPhaseWUsDone(phaseWUs)) {
84
+ return WU_STATUS.DONE;
85
+ }
86
+ if (hasPhaseWUStatus(phaseWUs, WU_STATUS.IN_PROGRESS)) {
87
+ return WU_STATUS.IN_PROGRESS;
88
+ }
89
+ if (hasPhaseWUStatus(phaseWUs, WU_STATUS.BLOCKED)) {
90
+ return WU_STATUS.BLOCKED;
91
+ }
92
+ if (hasPhaseWUStatus(phaseWUs, WU_STATUS.READY)) {
93
+ return WU_STATUS.READY;
94
+ }
95
+ return normalizeLifecycleStatus(status) || WU_STATUS.IN_PROGRESS;
96
+ }
57
97
  function priorityRank(priority) {
58
98
  const p = String(priority || '').toUpperCase();
59
99
  const map = { P0: 0, P1: 1, P2: 2, P3: 3 };
@@ -75,7 +115,7 @@ function renderDetailed(initiative, useColor) {
75
115
  const wuById = new Map(wus.map((wu) => [wu.id, wu]));
76
116
  const phaseGroups = getInitiativePhases(id);
77
117
  const phases = toInitiativePhases(doc);
78
- const status = deriveInitiativeLifecycleStatus(doc.status, phases);
118
+ const status = deriveInitiativeLifecycleStatus(doc.status, phases, progress);
79
119
  const docTitle = asString(doc.title);
80
120
  const rawStatus = asString(doc.status);
81
121
  const normalizedRawStatus = normalizeLifecycleStatus(rawStatus);
@@ -129,7 +169,7 @@ function renderDetailed(initiative, useColor) {
129
169
  console.log('\nPhases:');
130
170
  for (const phase of phases) {
131
171
  const phaseWUs = phaseGroups.get(phase.id) || [];
132
- const phaseStatus = formatStatus(normalizeLifecycleStatus(phase.status), useColor);
172
+ const phaseStatus = formatStatus(deriveInitiativePhaseStatus(phase.status, phaseWUs), useColor);
133
173
  const phaseTitle = asString(phase.title) || `Phase ${phase.id}`;
134
174
  console.log(` ${phase.id}. ${phaseTitle.padEnd(30)} [${phaseStatus}] ${phaseWUs.length} WUs`);
135
175
  }
@@ -169,7 +209,7 @@ function renderJSON(initiative) {
169
209
  const wus = getInitiativeWUs(id);
170
210
  const phaseGroups = getInitiativePhases(id);
171
211
  const phases = toInitiativePhases(doc);
172
- const status = deriveInitiativeLifecycleStatus(doc.status, phases);
212
+ const status = deriveInitiativeLifecycleStatus(doc.status, phases, progress);
173
213
  const output = {
174
214
  id,
175
215
  slug: asString(doc.slug),
@@ -191,10 +231,11 @@ function renderJSON(initiative) {
191
231
  },
192
232
  phases: phases.map((phase) => {
193
233
  const phaseWUs = phaseGroups.get(phase.id) || [];
234
+ const phaseStatus = deriveInitiativePhaseStatus(phase.status, phaseWUs);
194
235
  return {
195
236
  id: phase.id,
196
237
  title: asString(phase.title),
197
- status: normalizeLifecycleStatus(phase.status),
238
+ status: phaseStatus,
198
239
  wuCount: phaseWUs.length,
199
240
  wus: phaseWUs.map((w) => ({
200
241
  id: w.id,
@@ -258,7 +299,7 @@ function truncate(str, maxLen) {
258
299
  function capitalizeFirst(str) {
259
300
  return str.charAt(0).toUpperCase() + str.slice(1).replace(/_/g, ' ');
260
301
  }
261
- async function main() {
302
+ export async function main() {
262
303
  const args = createWUParser({
263
304
  name: 'initiative-status',
264
305
  description: 'Show detailed initiative view with phases and WUs',
package/dist/lane-edit.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * @file lane-edit.ts
6
6
  * WU-1854: Safe in-place lane definition editing via micro-worktree
7
7
  *
8
- * Enables editing lane definitions in .lumenflow.config.yaml without
8
+ * Enables editing lane definitions in workspace.yaml without
9
9
  * directly writing to main. Uses the micro-worktree isolation pattern
10
10
  * (WU-1262) to commit changes atomically.
11
11
  *
@@ -19,11 +19,13 @@
19
19
  import path from 'node:path';
20
20
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
21
21
  import YAML from 'yaml';
22
- import { findProjectRoot } from '@lumenflow/core/config';
22
+ import { findProjectRoot, WORKSPACE_CONFIG_FILE_NAME } from '@lumenflow/core/config';
23
+ import { WORKSPACE_V2_KEYS } from '@lumenflow/core/config-schema';
23
24
  import { die } from '@lumenflow/core/error-handler';
24
- import { CONFIG_FILES, FILE_SYSTEM } from '@lumenflow/core/wu-constants';
25
+ import { FILE_SYSTEM } from '@lumenflow/core/wu-constants';
25
26
  import { withMicroWorktree } from '@lumenflow/core/micro-worktree';
26
27
  import { runCLI } from './cli-entry-point.js';
28
+ import { asRecord } from './object-guards.js';
27
29
  import { validateLaneArtifacts, classifyLaneLifecycleForProject, LANE_LIFECYCLE_STATUS, } from './lane-lifecycle-process.js';
28
30
  // ---------------------------------------------------------------------------
29
31
  // Constants
@@ -38,12 +40,13 @@ const ARG_REMOVE_PATH = '--remove-path';
38
40
  const ARG_DESCRIPTION = '--description';
39
41
  const ARG_HELP = '--help';
40
42
  const COMMIT_PREFIX = 'chore: lane:edit';
43
+ const SOFTWARE_DELIVERY_KEY = WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY;
41
44
  // ---------------------------------------------------------------------------
42
45
  // Help
43
46
  // ---------------------------------------------------------------------------
44
47
  const HELP_TEXT = `Usage: pnpm lane:edit --name <lane> [options]
45
48
 
46
- Edit a lane definition in .lumenflow.config.yaml via micro-worktree commit.
49
+ Edit a lane definition in workspace.yaml via micro-worktree commit.
47
50
 
48
51
  Required:
49
52
  ${ARG_NAME} <name> Target lane name (exact match)
@@ -135,11 +138,11 @@ export function parseLaneEditArgs(argv) {
135
138
  // Precondition validation
136
139
  // ---------------------------------------------------------------------------
137
140
  export function validateLaneEditPreconditions(projectRoot) {
138
- const configPath = path.join(projectRoot, CONFIG_FILES.LUMENFLOW_CONFIG);
141
+ const configPath = path.join(projectRoot, WORKSPACE_CONFIG_FILE_NAME);
139
142
  if (!existsSync(configPath)) {
140
143
  return {
141
144
  ok: false,
142
- error: `${LOG_PREFIX} Missing ${CONFIG_FILES.LUMENFLOW_CONFIG}. Run \`pnpm exec lumenflow init\` first.`,
145
+ error: `${LOG_PREFIX} Missing ${WORKSPACE_CONFIG_FILE_NAME}. Run \`pnpm workspace-init --yes\` first.`,
143
146
  };
144
147
  }
145
148
  const classification = classifyLaneLifecycleForProject(projectRoot);
@@ -226,11 +229,17 @@ export function applyLaneEdit(definitions, options) {
226
229
  // ---------------------------------------------------------------------------
227
230
  function readConfigDoc(configPath) {
228
231
  const content = readFileSync(configPath, FILE_SYSTEM.UTF8);
229
- const parsed = YAML.parse(content);
230
- return parsed && typeof parsed === 'object' ? parsed : {};
232
+ const workspace = asRecord(YAML.parse(content));
233
+ if (!workspace) {
234
+ return {};
235
+ }
236
+ return asRecord(workspace[SOFTWARE_DELIVERY_KEY]) ?? {};
231
237
  }
232
238
  function writeConfigDoc(configPath, config) {
233
- const nextContent = YAML.stringify(config);
239
+ const content = readFileSync(configPath, FILE_SYSTEM.UTF8);
240
+ const workspace = asRecord(YAML.parse(content)) ?? {};
241
+ workspace[SOFTWARE_DELIVERY_KEY] = config;
242
+ const nextContent = YAML.stringify(workspace);
234
243
  writeFileSync(configPath, nextContent, FILE_SYSTEM.UTF8);
235
244
  }
236
245
  // ---------------------------------------------------------------------------
@@ -275,7 +284,7 @@ async function main() {
275
284
  logPrefix: LOG_PREFIX,
276
285
  pushOnly: true,
277
286
  async execute({ worktreePath }) {
278
- const configRelPath = CONFIG_FILES.LUMENFLOW_CONFIG;
287
+ const configRelPath = WORKSPACE_CONFIG_FILE_NAME;
279
288
  const configPath = path.join(worktreePath, configRelPath);
280
289
  if (!existsSync(configPath)) {
281
290
  die(`${LOG_PREFIX} Config file not found in micro-worktree: ${configRelPath}`);