@lumenflow/cli 3.12.6 → 3.12.8

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 (111) hide show
  1. package/dist/config-set.js +82 -32
  2. package/dist/config-set.js.map +1 -1
  3. package/dist/wu-claim.js +2 -1
  4. package/dist/wu-claim.js.map +1 -1
  5. package/dist/wu-done-policies.js +9 -9
  6. package/dist/wu-done-policies.js.map +1 -1
  7. package/dist/wu-spawn-strategy-resolver.js +14 -6
  8. package/dist/wu-spawn-strategy-resolver.js.map +1 -1
  9. package/package.json +8 -8
  10. package/packs/sidekick/.turbo/turbo-build.log +1 -1
  11. package/packs/sidekick/package.json +1 -1
  12. package/packs/software-delivery/.turbo/turbo-build.log +1 -1
  13. package/packs/software-delivery/package.json +1 -1
  14. package/dist/chunk-2D2VOCA4.js +0 -37
  15. package/dist/chunk-2D5KFYGX.js +0 -284
  16. package/dist/chunk-2GXVIN57.js +0 -14072
  17. package/dist/chunk-2MQ7HZWZ.js +0 -26
  18. package/dist/chunk-2UFQ3A3C.js +0 -643
  19. package/dist/chunk-3RG5ZIWI.js +0 -10
  20. package/dist/chunk-4N74J3UT.js +0 -15
  21. package/dist/chunk-5GTOXFYR.js +0 -392
  22. package/dist/chunk-5VY6MQMC.js +0 -240
  23. package/dist/chunk-67XVPMRY.js +0 -1297
  24. package/dist/chunk-6HO4GWJE.js +0 -164
  25. package/dist/chunk-6W5XHWYV.js +0 -1890
  26. package/dist/chunk-6X4EMYJQ.js +0 -64
  27. package/dist/chunk-6XYXI2NQ.js +0 -772
  28. package/dist/chunk-7ANSOV6Q.js +0 -285
  29. package/dist/chunk-A624LFLB.js +0 -1380
  30. package/dist/chunk-ADN5NHG4.js +0 -126
  31. package/dist/chunk-B7YJYJKG.js +0 -33
  32. package/dist/chunk-CCLHCPKG.js +0 -210
  33. package/dist/chunk-CK36VROC.js +0 -1584
  34. package/dist/chunk-D3UOFRSB.js +0 -81
  35. package/dist/chunk-DFR4DJBM.js +0 -230
  36. package/dist/chunk-DSYBDHYH.js +0 -79
  37. package/dist/chunk-DWMLTXKQ.js +0 -1176
  38. package/dist/chunk-E3REJTAJ.js +0 -28
  39. package/dist/chunk-EA3IVO64.js +0 -633
  40. package/dist/chunk-EK2AKZKD.js +0 -55
  41. package/dist/chunk-ELD7JTTT.js +0 -343
  42. package/dist/chunk-EX6TT2XI.js +0 -195
  43. package/dist/chunk-EXINSFZE.js +0 -82
  44. package/dist/chunk-EZ6ZBYBM.js +0 -510
  45. package/dist/chunk-FBKAPTJ2.js +0 -16
  46. package/dist/chunk-FVLV5RYH.js +0 -1118
  47. package/dist/chunk-GDNSBQVK.js +0 -2485
  48. package/dist/chunk-GPQHMBNN.js +0 -278
  49. package/dist/chunk-GTFJB67L.js +0 -68
  50. package/dist/chunk-HANJXVKW.js +0 -1127
  51. package/dist/chunk-HEVS5YLD.js +0 -269
  52. package/dist/chunk-HMEVZKPQ.js +0 -9
  53. package/dist/chunk-HRGSYNLM.js +0 -3511
  54. package/dist/chunk-ISZR5N4K.js +0 -60
  55. package/dist/chunk-J6SUPR2C.js +0 -226
  56. package/dist/chunk-JERYVEIZ.js +0 -244
  57. package/dist/chunk-JHHWGL2N.js +0 -87
  58. package/dist/chunk-JONWQUB5.js +0 -775
  59. package/dist/chunk-K2DIWWDM.js +0 -1766
  60. package/dist/chunk-KY4PGL5V.js +0 -969
  61. package/dist/chunk-L737LQ4C.js +0 -1285
  62. package/dist/chunk-LFTWYIB2.js +0 -497
  63. package/dist/chunk-LV47RFNJ.js +0 -41
  64. package/dist/chunk-MKSAITI7.js +0 -15
  65. package/dist/chunk-MZ7RKIX4.js +0 -212
  66. package/dist/chunk-NAP6CFSO.js +0 -84
  67. package/dist/chunk-ND6MY37M.js +0 -16
  68. package/dist/chunk-NMG736UR.js +0 -683
  69. package/dist/chunk-NRAXROED.js +0 -32
  70. package/dist/chunk-NRIZR3A7.js +0 -690
  71. package/dist/chunk-NX43BG3M.js +0 -233
  72. package/dist/chunk-O645XLSI.js +0 -297
  73. package/dist/chunk-OMJD6A3S.js +0 -235
  74. package/dist/chunk-QB6SJD4T.js +0 -430
  75. package/dist/chunk-QFSTL4J3.js +0 -276
  76. package/dist/chunk-QLGDFMFX.js +0 -212
  77. package/dist/chunk-RIAAGL2E.js +0 -13
  78. package/dist/chunk-RWO5XMZ6.js +0 -86
  79. package/dist/chunk-RXRKBBSM.js +0 -149
  80. package/dist/chunk-RZOZMML6.js +0 -363
  81. package/dist/chunk-U7I7FS7T.js +0 -113
  82. package/dist/chunk-UI42RODY.js +0 -717
  83. package/dist/chunk-UTVMVSCO.js +0 -519
  84. package/dist/chunk-V6OJGLBA.js +0 -1746
  85. package/dist/chunk-W2JHVH7D.js +0 -152
  86. package/dist/chunk-WD3Y7VQN.js +0 -280
  87. package/dist/chunk-WOCTQ5MS.js +0 -303
  88. package/dist/chunk-WZR3ZUNN.js +0 -696
  89. package/dist/chunk-XGI665H7.js +0 -150
  90. package/dist/chunk-XKY65P2T.js +0 -304
  91. package/dist/chunk-Y4CQZY65.js +0 -57
  92. package/dist/chunk-YFEXKLVE.js +0 -194
  93. package/dist/chunk-YHO3HS5X.js +0 -287
  94. package/dist/chunk-YLS7AZSX.js +0 -738
  95. package/dist/chunk-ZE473AO6.js +0 -49
  96. package/dist/chunk-ZF747T3O.js +0 -644
  97. package/dist/chunk-ZHCZHZH3.js +0 -43
  98. package/dist/chunk-ZZNZX2XY.js +0 -87
  99. package/dist/constants-7QAP3VQ4.js +0 -23
  100. package/dist/dist-IY3UUMWK.js +0 -33
  101. package/dist/invariants-runner-W5RGHCSU.js +0 -27
  102. package/dist/lane-lock-6J36HD5O.js +0 -35
  103. package/dist/mem-checkpoint-core-EANG2GVN.js +0 -14
  104. package/dist/mem-signal-core-2LZ2WYHW.js +0 -19
  105. package/dist/memory-store-OLB5FO7K.js +0 -18
  106. package/dist/service-6BYCOCO5.js +0 -13
  107. package/dist/spawn-policy-resolver-NTSZYQ6R.js +0 -17
  108. package/dist/spawn-task-builder-R4E2BHSW.js +0 -22
  109. package/dist/wu-done-pr-WLFFFEPJ.js +0 -25
  110. package/dist/wu-done-validation-3J5E36FE.js +0 -30
  111. package/dist/wu-duplicate-id-detector-5S7JHELK.js +0 -232
@@ -1,1380 +0,0 @@
1
- import {
2
- integrateClaudeCode
3
- } from "./chunk-5GTOXFYR.js";
4
- import {
5
- generateSessionStartRecoveryScript
6
- } from "./chunk-EA3IVO64.js";
7
- import {
8
- CANONICAL_BOOTSTRAP_COMMAND,
9
- DEFAULT_PROJECT_NAME,
10
- WORKSPACE_FILENAME,
11
- getDefaultWorkspaceConfig
12
- } from "./chunk-WOCTQ5MS.js";
13
- import {
14
- createDirectory,
15
- createExecutableScript,
16
- createFile,
17
- loadTemplate,
18
- processTemplate
19
- } from "./chunk-HEVS5YLD.js";
20
- import {
21
- AGENTS_MD_TEMPLATE,
22
- AIDER_CONF_TEMPLATE,
23
- BACKLOG_TEMPLATE,
24
- CLAUDE_MD_TEMPLATE,
25
- CLAUDE_SETTINGS_TEMPLATE,
26
- CLINE_RULES_TEMPLATE,
27
- CURSOR_RULES_TEMPLATE,
28
- DEFAULT_LANE_DEFINITIONS,
29
- FRAMEWORK_HINT_TEMPLATE,
30
- FRAMEWORK_OVERLAY_TEMPLATE,
31
- GATE_STUB_SCRIPTS,
32
- GITIGNORE_TEMPLATE,
33
- LANE_LIFECYCLE_STATUS,
34
- LUMENFLOW_GATES_SKILL_TEMPLATE,
35
- MCP_JSON_TEMPLATE,
36
- PRETTIERIGNORE_TEMPLATE,
37
- PRE_COMMIT_TEMPLATE,
38
- REQUIRED_GITIGNORE_EXCLUSIONS,
39
- SAFE_GIT_TEMPLATE,
40
- SCRIPT_ARG_OVERRIDES,
41
- STATUS_TEMPLATE,
42
- WINDSURF_RULES_TEMPLATE,
43
- WORKTREE_DISCIPLINE_SKILL_TEMPLATE,
44
- WU_LIFECYCLE_SKILL_TEMPLATE,
45
- WU_TEMPLATE_YAML,
46
- buildInitLaneLifecycleMessage
47
- } from "./chunk-67XVPMRY.js";
48
- import {
49
- getPublicManifest
50
- } from "./chunk-KY4PGL5V.js";
51
- import {
52
- SCAFFOLDED_ONBOARDING_TEMPLATE_PATHS
53
- } from "./chunk-FBKAPTJ2.js";
54
- import {
55
- isInWorktree,
56
- isMainBranch
57
- } from "./chunk-E3REJTAJ.js";
58
- import {
59
- runDoctorForInit
60
- } from "./chunk-ZF747T3O.js";
61
- import {
62
- WU_OPTIONS,
63
- createWUParser,
64
- runCLI
65
- } from "./chunk-2GXVIN57.js";
66
- import {
67
- CLAUDE_HOOKS,
68
- ENV_VARS
69
- } from "./chunk-DWMLTXKQ.js";
70
- import {
71
- GATE_PRESETS,
72
- GIT_DIRECTORY_NAME,
73
- LUMENFLOW_CLIENT_IDS,
74
- WORKSPACE_V2_KEYS,
75
- getDefaultConfig,
76
- getDocsLayoutPreset
77
- } from "./chunk-V6OJGLBA.js";
78
- import {
79
- ErrorCodes,
80
- createError
81
- } from "./chunk-RXRKBBSM.js";
82
-
83
- // src/init.ts
84
- import * as fs2 from "fs";
85
- import * as path2 from "path";
86
- import * as yaml from "yaml";
87
- import { execFileSync as execFileSync2 } from "child_process";
88
-
89
- // src/init-detection.ts
90
- import * as fs from "fs";
91
- import * as path from "path";
92
- import { execFileSync } from "child_process";
93
- var DEFAULT_CLIENT_CLAUDE = LUMENFLOW_CLIENT_IDS.CLAUDE_CODE;
94
- function detectIDEEnvironment() {
95
- if (process.env[ENV_VARS.CLAUDE_PROJECT_DIR] || process.env[ENV_VARS.CLAUDE_CODE]) {
96
- return "claude";
97
- }
98
- const cursorVars = Object.keys(process.env).filter((key) => key.startsWith("CURSOR_"));
99
- if (cursorVars.length > 0) {
100
- return "cursor";
101
- }
102
- const windsurfVars = Object.keys(process.env).filter((key) => key.startsWith("WINDSURF_"));
103
- if (windsurfVars.length > 0) {
104
- return "windsurf";
105
- }
106
- const vscodeVars = Object.keys(process.env).filter((key) => key.startsWith("VSCODE_"));
107
- if (vscodeVars.length > 0) {
108
- return "vscode";
109
- }
110
- return void 0;
111
- }
112
- function getCommandVersion(command, args) {
113
- try {
114
- const output = execFileSync(command, args, {
115
- encoding: "utf-8",
116
- stdio: ["pipe", "pipe", "pipe"]
117
- }).trim();
118
- return output;
119
- } catch {
120
- return "not found";
121
- }
122
- }
123
- function parseVersion(versionStr) {
124
- const match = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(versionStr);
125
- if (!match) {
126
- return [0, 0, 0];
127
- }
128
- return [parseInt(match[1], 10), parseInt(match[2], 10), parseInt(match[3] || "0", 10)];
129
- }
130
- function compareVersions(actual, required) {
131
- const actualParts = parseVersion(actual);
132
- const requiredParts = parseVersion(required);
133
- for (let i = 0; i < 3; i++) {
134
- if (actualParts[i] > requiredParts[i]) {
135
- return true;
136
- }
137
- if (actualParts[i] < requiredParts[i]) {
138
- return false;
139
- }
140
- }
141
- return true;
142
- }
143
- function checkPrerequisites() {
144
- const nodeVersion = getCommandVersion("node", ["--version"]);
145
- const pnpmVersion = getCommandVersion("pnpm", ["--version"]);
146
- const gitVersion = getCommandVersion("git", ["--version"]);
147
- const requiredNode = "22.0.0";
148
- const requiredPnpm = "9.0.0";
149
- const requiredGit = "2.0.0";
150
- const nodeOk = nodeVersion !== "not found" && compareVersions(nodeVersion, requiredNode);
151
- const pnpmOk = pnpmVersion !== "not found" && compareVersions(pnpmVersion, requiredPnpm);
152
- const gitOk = gitVersion !== "not found" && compareVersions(gitVersion, requiredGit);
153
- return {
154
- node: {
155
- passed: nodeOk,
156
- version: nodeVersion,
157
- required: `>=${requiredNode}`,
158
- message: nodeOk ? void 0 : `Node.js ${requiredNode}+ required`
159
- },
160
- pnpm: {
161
- passed: pnpmOk,
162
- version: pnpmVersion,
163
- required: `>=${requiredPnpm}`,
164
- message: pnpmOk ? void 0 : `pnpm ${requiredPnpm}+ required`
165
- },
166
- git: {
167
- passed: gitOk,
168
- version: gitVersion,
169
- required: `>=${requiredGit}`,
170
- message: gitOk ? void 0 : `Git ${requiredGit}+ required`
171
- }
172
- };
173
- }
174
- function getDocsPath(structure) {
175
- return getDocsLayoutPreset(structure);
176
- }
177
- function detectDocsStructure(targetDir) {
178
- const docsDir = path.join(targetDir, "docs");
179
- if (!fs.existsSync(docsDir)) {
180
- return "simple";
181
- }
182
- const entries = fs.readdirSync(docsDir);
183
- const hasNumberedDir = entries.some((entry) => /^\d{2}-/.test(entry));
184
- if (hasNumberedDir) {
185
- return "arc42";
186
- }
187
- return "simple";
188
- }
189
- function detectDefaultClient() {
190
- if (process.env[ENV_VARS.CLAUDE_PROJECT_DIR] || process.env[ENV_VARS.CLAUDE_CODE]) {
191
- return DEFAULT_CLIENT_CLAUDE;
192
- }
193
- return "none";
194
- }
195
- function isGitRepo(targetDir) {
196
- try {
197
- execFileSync("git", ["rev-parse", "--git-dir"], {
198
- cwd: targetDir,
199
- stdio: "pipe"
200
- });
201
- return true;
202
- } catch {
203
- return false;
204
- }
205
- }
206
- function hasGitCommits(targetDir) {
207
- try {
208
- execFileSync("git", ["rev-parse", "HEAD"], {
209
- cwd: targetDir,
210
- stdio: "pipe"
211
- });
212
- return true;
213
- } catch {
214
- return false;
215
- }
216
- }
217
- function hasOriginRemote(targetDir) {
218
- try {
219
- const result = execFileSync("git", ["remote", "get-url", "origin"], {
220
- cwd: targetDir,
221
- encoding: "utf-8",
222
- stdio: "pipe"
223
- });
224
- return result.trim().length > 0;
225
- } catch {
226
- return false;
227
- }
228
- }
229
- function detectGitStateConfig(targetDir) {
230
- if (!isGitRepo(targetDir)) {
231
- return { requireRemote: false };
232
- }
233
- if (!hasOriginRemote(targetDir)) {
234
- return { requireRemote: false };
235
- }
236
- return null;
237
- }
238
-
239
- // src/init.ts
240
- var INIT_OPTIONS = {
241
- full: {
242
- name: "full",
243
- flags: "--full",
244
- description: "Add docs + agent onboarding + task scaffolding (default: true)"
245
- },
246
- minimal: {
247
- name: "minimal",
248
- flags: "--minimal",
249
- description: "Skip agent onboarding docs (only core files)"
250
- },
251
- framework: {
252
- name: "framework",
253
- flags: "--framework <name>",
254
- description: "Add framework hint + overlay docs"
255
- },
256
- // WU-1171: --client is the new primary flag (wu:spawn vocabulary)
257
- client: {
258
- name: "client",
259
- flags: "--client <type>",
260
- description: "Client type (claude, cursor, windsurf, codex, all, none)"
261
- },
262
- // WU-1171: --vendor kept as backward-compatible alias
263
- vendor: {
264
- name: "vendor",
265
- flags: "--vendor <type>",
266
- description: "Alias for --client (deprecated)"
267
- },
268
- // WU-1171: --merge mode for safe insertion into existing files
269
- merge: {
270
- name: "merge",
271
- flags: "--merge",
272
- description: "Merge LumenFlow config into existing files using bounded markers"
273
- },
274
- preset: {
275
- name: "preset",
276
- flags: "--preset <preset>",
277
- description: "Gate preset for config (node, python, go, rust, dotnet)"
278
- },
279
- bootstrapDomain: {
280
- name: "bootstrapDomain",
281
- flags: "--bootstrap-domain <domain>",
282
- description: "Bootstrap domain: software-delivery, infra, or custom"
283
- },
284
- skipBootstrap: {
285
- name: "skipBootstrap",
286
- flags: "--skip-bootstrap",
287
- description: "Skip workspace bootstrap-all flow (workspace.yaml + pack install)"
288
- },
289
- skipBootstrapPackInstall: {
290
- name: "skipBootstrapPackInstall",
291
- flags: "--skip-bootstrap-pack-install",
292
- description: "Skip registry pack install during bootstrap"
293
- },
294
- force: WU_OPTIONS.force
295
- };
296
- function parseBootstrapDomain(rawDomain) {
297
- if (!rawDomain) {
298
- return BOOTSTRAP_DEFAULT_DOMAIN;
299
- }
300
- if (BOOTSTRAP_VALID_DOMAINS.has(rawDomain)) {
301
- return rawDomain;
302
- }
303
- const validDomains = Array.from(BOOTSTRAP_VALID_DOMAINS).join(", ");
304
- throw createError(
305
- ErrorCodes.INVALID_ARGUMENT,
306
- `${BOOTSTRAP_ERROR_PREFIX} Invalid --bootstrap-domain "${rawDomain}". Valid values: ${validDomains}`
307
- );
308
- }
309
- function parseInitOptions() {
310
- const opts = createWUParser({
311
- name: "lumenflow-init",
312
- description: "Initialize LumenFlow in a project\n\nSubcommands:\n lumenflow commands List all available CLI commands\n lumenflow cloud connect Configure cloud control-plane access",
313
- options: Object.values(INIT_OPTIONS)
314
- });
315
- const clientValue = opts.client || opts.vendor;
316
- const fullMode = opts.minimal ? false : opts.full ?? true;
317
- const bootstrapDomain = parseBootstrapDomain(opts.bootstrapDomain);
318
- return {
319
- force: opts.force ?? false,
320
- full: fullMode,
321
- merge: opts.merge ?? false,
322
- framework: opts.framework,
323
- client: clientValue,
324
- vendor: clientValue,
325
- preset: opts.preset,
326
- bootstrapDomain,
327
- skipBootstrap: Boolean(opts.skipBootstrap),
328
- skipBootstrapPackInstall: Boolean(opts.skipBootstrapPackInstall)
329
- };
330
- }
331
- var DEFAULT_CLIENT_CLAUDE2 = LUMENFLOW_CLIENT_IDS.CLAUDE_CODE;
332
- var BOOTSTRAP_DEFAULT_DOMAIN = "software-delivery";
333
- var BOOTSTRAP_INFRA_DOMAIN = "infra";
334
- var BOOTSTRAP_CUSTOM_DOMAIN = "custom";
335
- var BOOTSTRAP_VALID_DOMAINS = /* @__PURE__ */ new Set([
336
- BOOTSTRAP_DEFAULT_DOMAIN,
337
- BOOTSTRAP_INFRA_DOMAIN,
338
- BOOTSTRAP_CUSTOM_DOMAIN
339
- ]);
340
- var BOOTSTRAP_SKIP_REASON_FLAG = "--skip-bootstrap";
341
- var BOOTSTRAP_SKIP_REASON_EXISTING_WORKSPACE = `${WORKSPACE_FILENAME} already exists`;
342
- var BOOTSTRAP_ERROR_PREFIX = "[lumenflow bootstrap]";
343
- var INIT_SUBCOMMANDS = {
344
- COMMANDS: "commands",
345
- CLOUD: "cloud"
346
- };
347
- var LEGACY_SUBCOMMANDS = {
348
- ONBOARD: "onboard",
349
- WORKSPACE_INIT_COLON: "workspace:init",
350
- WORKSPACE_INIT_DASH: "workspace-init"
351
- };
352
- var CLOUD_SUBCOMMANDS = {
353
- CONNECT: "connect"
354
- };
355
- var CLOUD_CONNECT_BIN = "cloud-connect";
356
- var INIT_ERROR_PREFIX = "[lumenflow init]";
357
- var INIT_CLOUD_CONNECT_HELP = "Usage: lumenflow cloud connect --endpoint <url> --org-id <id> --project-id <id> [--token-env <name>]";
358
- var LEGACY_SUBCOMMAND_ERROR_PREFIX = `${INIT_ERROR_PREFIX} Legacy onboarding subcommand`;
359
- var LEGACY_SUBCOMMAND_GUIDANCE = `Use "${CANONICAL_BOOTSTRAP_COMMAND}" for bootstrap-all onboarding`;
360
- var LEGACY_SUBCOMMAND_HELP_HINT = `Run "${CANONICAL_BOOTSTRAP_COMMAND} --help" for supported options`;
361
- var CONFIG_FILE_NAME = WORKSPACE_FILENAME;
362
- var SOFTWARE_DELIVERY_KEY = WORKSPACE_V2_KEYS.SOFTWARE_DELIVERY;
363
- var SOFTWARE_DELIVERY_CONFIG_KEYS = {
364
- AGENTS: "agents",
365
- CLIENTS: "clients",
366
- ENFORCEMENT: "enforcement"
367
- };
368
- var FRAMEWORK_HINT_FILE = ".lumenflow.framework.yaml";
369
- var LUMENFLOW_DIR = ".lumenflow";
370
- var LUMENFLOW_AGENTS_DIR = `${LUMENFLOW_DIR}/agents`;
371
- var CLAUDE_DIR = ".claude";
372
- var CLAUDE_AGENTS_DIR = path2.join(CLAUDE_DIR, "agents");
373
- async function checkBranchGuard(targetDir, result) {
374
- result.warnings = result.warnings ?? [];
375
- const gitDir = path2.join(targetDir, GIT_DIRECTORY_NAME);
376
- if (!fs2.existsSync(gitDir)) {
377
- return;
378
- }
379
- if (isInWorktree({ cwd: targetDir })) {
380
- return;
381
- }
382
- try {
383
- const onMain = await isMainBranch();
384
- if (onMain) {
385
- result.warnings.push(
386
- "Running init on main branch in main checkout. Consider using a worktree for changes to tracked files."
387
- );
388
- }
389
- } catch {
390
- }
391
- }
392
- function detectProjectTooling(targetDir) {
393
- const packageJsonPath = path2.join(targetDir, "package.json");
394
- if (!fs2.existsSync(packageJsonPath)) {
395
- return { hasTurbo: false };
396
- }
397
- try {
398
- const content = fs2.readFileSync(packageJsonPath, "utf-8");
399
- const pkg = JSON.parse(content);
400
- const deps = pkg.dependencies ?? {};
401
- const devDeps = pkg.devDependencies ?? {};
402
- const allDeps = { ...deps, ...devDeps };
403
- let testRunner;
404
- if ("vitest" in allDeps) {
405
- testRunner = "vitest";
406
- } else if ("jest" in allDeps) {
407
- testRunner = "jest";
408
- } else if ("mocha" in allDeps) {
409
- testRunner = "mocha";
410
- }
411
- const hasTurbo = "turbo" in allDeps;
412
- let packageManager;
413
- const pkgManager = pkg.packageManager;
414
- if (pkgManager?.startsWith("pnpm")) {
415
- packageManager = "pnpm";
416
- } else if (pkgManager?.startsWith("yarn")) {
417
- packageManager = "yarn";
418
- } else if (pkgManager?.startsWith("bun")) {
419
- packageManager = "bun";
420
- } else if (pkgManager?.startsWith("npm")) {
421
- packageManager = "npm";
422
- }
423
- return { testRunner, hasTurbo, packageManager };
424
- } catch {
425
- return { hasTurbo: false };
426
- }
427
- }
428
- function asRecord(value) {
429
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
430
- }
431
- function mergeConfigDefaults(defaults, existing) {
432
- const merged = { ...defaults };
433
- for (const [key, existingValue] of Object.entries(existing)) {
434
- const defaultValue = merged[key];
435
- const existingRecord = asRecord(existingValue);
436
- const defaultRecord = asRecord(defaultValue);
437
- if (defaultRecord && existingRecord) {
438
- merged[key] = mergeConfigDefaults(defaultRecord, existingRecord);
439
- continue;
440
- }
441
- merged[key] = existingValue;
442
- }
443
- return merged;
444
- }
445
- function toWorkspaceId(value) {
446
- return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
447
- }
448
- function loadWorkspaceDocument(targetDir) {
449
- const workspacePath = path2.join(targetDir, CONFIG_FILE_NAME);
450
- if (!fs2.existsSync(workspacePath)) {
451
- const projectName = resolveBootstrapProjectName(targetDir);
452
- const projectId = toWorkspaceId(projectName);
453
- const workspace2 = {
454
- ...getDefaultWorkspaceConfig(),
455
- id: projectId,
456
- name: projectName,
457
- memory_namespace: projectId,
458
- event_namespace: projectId
459
- };
460
- return { exists: false, workspace: workspace2 };
461
- }
462
- const content = fs2.readFileSync(workspacePath, "utf-8");
463
- const workspace = asRecord(yaml.parse(content));
464
- if (!workspace) {
465
- throw createError(
466
- ErrorCodes.WORKSPACE_MALFORMED,
467
- `${INIT_ERROR_PREFIX} ${CONFIG_FILE_NAME} exists but is not a valid YAML object. Fix ${CONFIG_FILE_NAME} and re-run init.`
468
- );
469
- }
470
- return { exists: true, workspace };
471
- }
472
- function upsertWorkspaceSoftwareDelivery(targetDir, softwareDeliveryConfig, result) {
473
- const workspacePath = path2.join(targetDir, CONFIG_FILE_NAME);
474
- const { exists, workspace } = loadWorkspaceDocument(targetDir);
475
- const existingSoftwareDelivery = asRecord(workspace[SOFTWARE_DELIVERY_KEY]) ?? {};
476
- workspace[SOFTWARE_DELIVERY_KEY] = mergeConfigDefaults(
477
- softwareDeliveryConfig,
478
- existingSoftwareDelivery
479
- );
480
- fs2.writeFileSync(workspacePath, yaml.stringify(workspace), "utf-8");
481
- if (exists) {
482
- result.overwritten = result.overwritten ?? [];
483
- if (!result.overwritten.includes(CONFIG_FILE_NAME)) {
484
- result.overwritten.push(CONFIG_FILE_NAME);
485
- }
486
- return;
487
- }
488
- result.created.push(CONFIG_FILE_NAME);
489
- }
490
- function buildSoftwareDeliveryConfig(gatePreset, gitConfigOverride, client, docsPaths, targetDir) {
491
- const config = getDefaultConfig();
492
- config.directories.agentsDir = LUMENFLOW_AGENTS_DIR;
493
- if (docsPaths) {
494
- config.directories.wuDir = `${docsPaths.tasks}/wu`;
495
- config.directories.initiativesDir = `${docsPaths.tasks}/initiatives`;
496
- config.directories.backlogPath = `${docsPaths.tasks}/backlog.md`;
497
- config.directories.statusPath = `${docsPaths.tasks}/status.md`;
498
- config.directories.plansDir = `${docsPaths.operations}/plans`;
499
- config.directories.onboardingDir = docsPaths.onboarding;
500
- config.directories.completeGuidePath = docsPaths.completeGuidePath;
501
- config.directories.quickRefPath = docsPaths.quickRefPath;
502
- config.directories.startingPromptPath = docsPaths.startingPromptPath;
503
- config.directories.governancePath = docsPaths.governancePath;
504
- }
505
- if (gatePreset && GATE_PRESETS[gatePreset]) {
506
- const presetConfig = GATE_PRESETS[gatePreset];
507
- config.gates.execution = {
508
- preset: gatePreset,
509
- ...presetConfig
510
- };
511
- }
512
- config.lanes = {
513
- lifecycle: {
514
- status: LANE_LIFECYCLE_STATUS.UNCONFIGURED
515
- }
516
- };
517
- if (gitConfigOverride) {
518
- config.git = {
519
- requireRemote: gitConfigOverride.requireRemote
520
- };
521
- }
522
- if (targetDir) {
523
- const tooling = detectProjectTooling(targetDir);
524
- if (tooling.testRunner) {
525
- config.test_runner = tooling.testRunner;
526
- } else {
527
- config.test_runner = "jest";
528
- }
529
- const pm = tooling.packageManager ?? "pnpm";
530
- const commands = {};
531
- if (tooling.hasTurbo) {
532
- commands.test_full = `${pm} turbo run test`;
533
- } else {
534
- commands.test_full = `${pm} test`;
535
- }
536
- if (tooling.testRunner === "vitest") {
537
- commands.test_incremental = `${pm} vitest run --changed origin/main`;
538
- } else if (tooling.testRunner === "jest") {
539
- commands.test_incremental = `${pm} jest --onlyChanged`;
540
- } else {
541
- commands.test_incremental = `${pm} test`;
542
- }
543
- config.gates.commands = {
544
- ...config.gates.commands,
545
- ...commands
546
- };
547
- }
548
- if (client === "claude") {
549
- config.agents = {
550
- clients: {
551
- [DEFAULT_CLIENT_CLAUDE2]: {
552
- enforcement: {
553
- hooks: true,
554
- block_outside_worktree: true,
555
- require_wu_for_edits: true,
556
- warn_on_stop_without_wu_done: true
557
- }
558
- }
559
- }
560
- };
561
- }
562
- return config;
563
- }
564
- function getCurrentDate() {
565
- return (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
566
- }
567
- function normalizeFrameworkName(framework) {
568
- const name = framework.trim();
569
- const slug = name.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
570
- if (!slug) {
571
- throw createError(ErrorCodes.INVALID_ARGUMENT, `Invalid framework name: "${framework}"`);
572
- }
573
- return { name, slug };
574
- }
575
- function resolveClientType(client, vendor, defaultClient) {
576
- if (client) {
577
- return client;
578
- }
579
- if (vendor) {
580
- return vendor;
581
- }
582
- return defaultClient === DEFAULT_CLIENT_CLAUDE2 ? "claude" : "none";
583
- }
584
- function getFileMode(options) {
585
- if (options.force) {
586
- return "force";
587
- }
588
- if (options.merge) {
589
- return "merge";
590
- }
591
- return "skip";
592
- }
593
- var CLIENT_INTEGRATIONS = {
594
- [LUMENFLOW_CLIENT_IDS.CLAUDE_CODE]: {
595
- run: (projectDir, enforcement) => integrateClaudeCode(projectDir, { enforcement })
596
- }
597
- // When new clients gain enforcement: add adapter entry here.
598
- };
599
- async function runClientIntegrations(targetDir, result) {
600
- const integrationFiles = [];
601
- const configPath = path2.join(targetDir, CONFIG_FILE_NAME);
602
- if (!fs2.existsSync(configPath)) return integrationFiles;
603
- let softwareDeliveryConfig;
604
- try {
605
- const content = fs2.readFileSync(configPath, "utf-8");
606
- const workspaceConfig = asRecord(yaml.parse(content));
607
- softwareDeliveryConfig = workspaceConfig ? asRecord(workspaceConfig[SOFTWARE_DELIVERY_KEY]) : null;
608
- } catch {
609
- return integrationFiles;
610
- }
611
- if (!softwareDeliveryConfig) return integrationFiles;
612
- const agents = asRecord(softwareDeliveryConfig[SOFTWARE_DELIVERY_CONFIG_KEYS.AGENTS]);
613
- const clients = asRecord(agents?.[SOFTWARE_DELIVERY_CONFIG_KEYS.CLIENTS]);
614
- if (!clients) return integrationFiles;
615
- for (const [clientKey, unsafeClientConfig] of Object.entries(clients)) {
616
- const clientConfig = asRecord(unsafeClientConfig);
617
- if (!clientConfig) {
618
- continue;
619
- }
620
- const enforcement = asRecord(
621
- clientConfig[SOFTWARE_DELIVERY_CONFIG_KEYS.ENFORCEMENT]
622
- );
623
- if (!enforcement?.hooks) continue;
624
- const integration = CLIENT_INTEGRATIONS[clientKey];
625
- if (!integration) continue;
626
- const createdFiles = await integration.run(targetDir, enforcement);
627
- integrationFiles.push(...createdFiles);
628
- }
629
- result.created.push(...integrationFiles);
630
- result.integrationFiles = integrationFiles;
631
- return integrationFiles;
632
- }
633
- function createInitialCommitIfNeeded(targetDir) {
634
- if (!isGitRepo(targetDir) || hasGitCommits(targetDir)) {
635
- return false;
636
- }
637
- try {
638
- execFileSync2("git", ["add", "."], { cwd: targetDir, stdio: "pipe" });
639
- execFileSync2("git", ["commit", "-m", "chore: initialize LumenFlow project"], {
640
- cwd: targetDir,
641
- stdio: "pipe"
642
- });
643
- return true;
644
- } catch {
645
- return false;
646
- }
647
- }
648
- function renameMasterToMainIfNeeded(targetDir) {
649
- if (!isGitRepo(targetDir)) {
650
- return false;
651
- }
652
- try {
653
- const currentBranch = execFileSync2("git", ["branch", "--show-current"], {
654
- cwd: targetDir,
655
- encoding: "utf-8",
656
- stdio: "pipe"
657
- }).trim();
658
- if (currentBranch !== "master") {
659
- return false;
660
- }
661
- execFileSync2("git", ["branch", "-m", "master", "main"], {
662
- cwd: targetDir,
663
- stdio: "pipe"
664
- });
665
- return true;
666
- } catch {
667
- return false;
668
- }
669
- }
670
- async function scaffoldProject(targetDir, options) {
671
- const result = {
672
- created: [],
673
- skipped: [],
674
- merged: [],
675
- warnings: [],
676
- overwritten: []
677
- };
678
- await checkBranchGuard(targetDir, result);
679
- const defaultClient = options.defaultClient ?? detectDefaultClient();
680
- const client = resolveClientType(options.client, options.vendor, defaultClient);
681
- const fileMode = getFileMode(options);
682
- if (!fs2.existsSync(targetDir)) {
683
- fs2.mkdirSync(targetDir, { recursive: true });
684
- }
685
- const docsStructure = options.docsStructure ?? detectDocsStructure(targetDir);
686
- const docsPaths = getDocsPath(docsStructure);
687
- const gitConfigOverride = detectGitStateConfig(targetDir);
688
- const tokenDefaults = {
689
- DATE: getCurrentDate(),
690
- PROJECT_ROOT: "<project-root>",
691
- // WU-1309: Use portable placeholder
692
- QUICK_REF_LINK: docsPaths.quickRefLink,
693
- DOCS_OPERATIONS_PATH: docsPaths.operations,
694
- // WU-1309: For framework overlay
695
- DOCS_TASKS_PATH: docsPaths.tasks,
696
- DOCS_ONBOARDING_PATH: docsPaths.onboarding,
697
- DOCS_WU_DIR_PATH: `${docsPaths.tasks}/wu`,
698
- DOCS_TEMPLATES_DIR_PATH: `${docsPaths.tasks}/templates`,
699
- DOCS_BACKLOG_PATH: `${docsPaths.tasks}/backlog.md`,
700
- DOCS_STATUS_PATH: `${docsPaths.tasks}/status.md`
701
- };
702
- upsertWorkspaceSoftwareDelivery(
703
- targetDir,
704
- buildSoftwareDeliveryConfig(
705
- options.gatePreset,
706
- gitConfigOverride,
707
- client,
708
- docsPaths,
709
- targetDir
710
- ),
711
- result
712
- );
713
- try {
714
- const agentsTemplate = loadTemplate("core/AGENTS.md.template");
715
- await createFile(
716
- path2.join(targetDir, "AGENTS.md"),
717
- processTemplate(agentsTemplate, tokenDefaults),
718
- fileMode,
719
- result,
720
- targetDir
721
- );
722
- } catch {
723
- await createFile(
724
- path2.join(targetDir, "AGENTS.md"),
725
- processTemplate(AGENTS_MD_TEMPLATE, tokenDefaults),
726
- fileMode,
727
- result,
728
- targetDir
729
- );
730
- }
731
- await createFile(
732
- path2.join(targetDir, "LUMENFLOW.md"),
733
- processTemplate(loadTemplate("core/LUMENFLOW.md.template"), tokenDefaults),
734
- fileMode,
735
- result,
736
- targetDir
737
- );
738
- await createFile(
739
- path2.join(targetDir, LUMENFLOW_DIR, "constraints.md"),
740
- processTemplate(loadTemplate("core/.lumenflow/constraints.md.template"), tokenDefaults),
741
- fileMode,
742
- result,
743
- targetDir
744
- );
745
- await createDirectory(path2.join(targetDir, LUMENFLOW_AGENTS_DIR), result, targetDir);
746
- await createFile(
747
- path2.join(targetDir, LUMENFLOW_AGENTS_DIR, ".gitkeep"),
748
- "",
749
- options.force ? "force" : "skip",
750
- result,
751
- targetDir
752
- );
753
- await scaffoldGitignore(targetDir, options, result);
754
- await scaffoldPrettierignore(targetDir, options, result);
755
- await scaffoldSafetyScripts(targetDir, options, result);
756
- if (options.full) {
757
- await scaffoldFullDocs(targetDir, options, result, tokenDefaults);
758
- }
759
- if (options.framework) {
760
- await scaffoldFrameworkOverlay(targetDir, options, result, tokenDefaults);
761
- }
762
- await scaffoldClientFiles(targetDir, options, result, tokenDefaults, client);
763
- await injectPackageJsonScripts(targetDir, options, result);
764
- await runClientIntegrations(targetDir, result);
765
- const createdInitialCommit = createInitialCommitIfNeeded(targetDir);
766
- if (createdInitialCommit) {
767
- result.created.push("Initial git commit");
768
- }
769
- const renamedBranch = renameMasterToMainIfNeeded(targetDir);
770
- if (renamedBranch) {
771
- result.created.push("Renamed branch master -> main");
772
- }
773
- const uniqueParents = [
774
- ...new Set(DEFAULT_LANE_DEFINITIONS.map((lane) => lane.name.split(":")[0].trim()))
775
- ];
776
- console.log("");
777
- console.log(
778
- ' Lane naming format: "Parent: Sublane" (e.g., "Framework: Core", "Content: Documentation")'
779
- );
780
- console.log(` Valid parent names: ${uniqueParents.join(", ")}`);
781
- return result;
782
- }
783
- var GITIGNORE_FILE_NAME = ".gitignore";
784
- async function scaffoldGitignore(targetDir, options, result) {
785
- const gitignorePath = path2.join(targetDir, GITIGNORE_FILE_NAME);
786
- const fileMode = getFileMode(options);
787
- if ((fileMode === "merge" || fileMode === "skip") && fs2.existsSync(gitignorePath)) {
788
- const existingContent = fs2.readFileSync(gitignorePath, "utf-8");
789
- const linesToAdd = [];
790
- for (const { pattern, line } of REQUIRED_GITIGNORE_EXCLUSIONS) {
791
- if (!existingContent.includes(pattern)) {
792
- linesToAdd.push(line);
793
- }
794
- }
795
- if (linesToAdd.length > 0) {
796
- const separator = existingContent.endsWith("\n") ? "" : "\n";
797
- const lumenflowBlock = `${separator}
798
- # LumenFlow (auto-added)
799
- ${linesToAdd.join("\n")}
800
- `;
801
- fs2.writeFileSync(gitignorePath, existingContent + lumenflowBlock);
802
- result.merged = result.merged ?? [];
803
- result.merged.push(GITIGNORE_FILE_NAME);
804
- } else {
805
- result.skipped.push(GITIGNORE_FILE_NAME);
806
- }
807
- return;
808
- }
809
- await createFile(gitignorePath, GITIGNORE_TEMPLATE, fileMode, result, targetDir);
810
- }
811
- var PRETTIERIGNORE_FILE_NAME = ".prettierignore";
812
- async function scaffoldPrettierignore(targetDir, options, result) {
813
- const prettierignorePath = path2.join(targetDir, PRETTIERIGNORE_FILE_NAME);
814
- const fileMode = getFileMode(options);
815
- await createFile(prettierignorePath, PRETTIERIGNORE_TEMPLATE, fileMode, result, targetDir);
816
- }
817
- function generateLumenflowScripts() {
818
- const scripts = {};
819
- const manifest = getPublicManifest();
820
- for (const cmd of manifest) {
821
- scripts[cmd.name] = SCRIPT_ARG_OVERRIDES[cmd.name] ?? cmd.binName;
822
- }
823
- return scripts;
824
- }
825
- var SCRIPTS_DIR = "scripts";
826
- var SAFE_GIT_FILE = "safe-git";
827
- var HUSKY_DIR = ".husky";
828
- var PRE_COMMIT_FILE = "pre-commit";
829
- var SAFE_GIT_TEMPLATE_PATH = "core/scripts/safe-git.template";
830
- var PRE_COMMIT_TEMPLATE_PATH = "core/.husky/pre-commit.template";
831
- async function scaffoldSafetyScripts(targetDir, options, result) {
832
- const fileMode = getFileMode(options);
833
- const safeGitPath = path2.join(targetDir, SCRIPTS_DIR, SAFE_GIT_FILE);
834
- try {
835
- const safeGitTemplate = loadTemplate(SAFE_GIT_TEMPLATE_PATH);
836
- await createExecutableScript(safeGitPath, safeGitTemplate, fileMode, result, targetDir);
837
- } catch {
838
- await createExecutableScript(safeGitPath, SAFE_GIT_TEMPLATE, fileMode, result, targetDir);
839
- }
840
- const preCommitPath = path2.join(targetDir, HUSKY_DIR, PRE_COMMIT_FILE);
841
- try {
842
- const preCommitTemplate = loadTemplate(PRE_COMMIT_TEMPLATE_PATH);
843
- await createExecutableScript(preCommitPath, preCommitTemplate, fileMode, result, targetDir);
844
- } catch {
845
- await createExecutableScript(preCommitPath, PRE_COMMIT_TEMPLATE, fileMode, result, targetDir);
846
- }
847
- }
848
- var PRETTIER_VERSION = "^3.8.0";
849
- var PRETTIER_PACKAGE_NAME = "prettier";
850
- var CLI_PACKAGE_VERSION = "^3.0.0";
851
- var CLI_PACKAGE_NAME = "@lumenflow/cli";
852
- async function injectPackageJsonScripts(targetDir, options, result) {
853
- const packageJsonPath = path2.join(targetDir, "package.json");
854
- let packageJson;
855
- if (fs2.existsSync(packageJsonPath)) {
856
- const content = fs2.readFileSync(packageJsonPath, "utf-8");
857
- packageJson = JSON.parse(content);
858
- } else {
859
- packageJson = {
860
- name: path2.basename(targetDir),
861
- version: "0.0.1",
862
- private: true
863
- };
864
- }
865
- if (!packageJson.scripts || typeof packageJson.scripts !== "object") {
866
- packageJson.scripts = {};
867
- }
868
- const scripts = packageJson.scripts;
869
- let modified = false;
870
- const lumenflowScripts = generateLumenflowScripts();
871
- for (const [scriptName, scriptCommand] of Object.entries(lumenflowScripts)) {
872
- if (options.force || !(scriptName in scripts)) {
873
- if (!(scriptName in scripts)) {
874
- scripts[scriptName] = scriptCommand;
875
- modified = true;
876
- }
877
- }
878
- }
879
- for (const [scriptName, scriptCommand] of Object.entries(GATE_STUB_SCRIPTS)) {
880
- if (options.force) {
881
- scripts[scriptName] = scriptCommand;
882
- modified = true;
883
- } else if (!(scriptName in scripts)) {
884
- scripts[scriptName] = scriptCommand;
885
- modified = true;
886
- }
887
- }
888
- if (!packageJson.devDependencies || typeof packageJson.devDependencies !== "object") {
889
- packageJson.devDependencies = {};
890
- }
891
- const devDeps = packageJson.devDependencies;
892
- if (options.force || !(CLI_PACKAGE_NAME in devDeps)) {
893
- if (options.force && CLI_PACKAGE_NAME in devDeps) {
894
- devDeps[CLI_PACKAGE_NAME] = CLI_PACKAGE_VERSION;
895
- modified = true;
896
- } else if (!(CLI_PACKAGE_NAME in devDeps)) {
897
- devDeps[CLI_PACKAGE_NAME] = CLI_PACKAGE_VERSION;
898
- modified = true;
899
- }
900
- }
901
- if (options.force || !(PRETTIER_PACKAGE_NAME in devDeps)) {
902
- if (!(PRETTIER_PACKAGE_NAME in devDeps)) {
903
- devDeps[PRETTIER_PACKAGE_NAME] = PRETTIER_VERSION;
904
- modified = true;
905
- }
906
- }
907
- if (modified) {
908
- fs2.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
909
- result.created.push("package.json (scripts updated)");
910
- }
911
- }
912
- async function runPostScaffoldInstall(targetDir, options) {
913
- const packageJsonPath = path2.join(targetDir, "package.json");
914
- if (!fs2.existsSync(packageJsonPath)) {
915
- return { packageManager: "npm", command: "npm install", skipped: true };
916
- }
917
- let pm = "npm";
918
- try {
919
- const content = fs2.readFileSync(packageJsonPath, "utf-8");
920
- const pkg = JSON.parse(content);
921
- const pkgManager = pkg.packageManager;
922
- if (pkgManager?.startsWith("pnpm")) {
923
- pm = "pnpm";
924
- } else if (pkgManager?.startsWith("yarn")) {
925
- pm = "yarn";
926
- } else if (pkgManager?.startsWith("bun")) {
927
- pm = "bun";
928
- } else if (pkgManager?.startsWith("npm")) {
929
- pm = "npm";
930
- } else {
931
- if (fs2.existsSync(path2.join(targetDir, "pnpm-lock.yaml"))) {
932
- pm = "pnpm";
933
- } else if (fs2.existsSync(path2.join(targetDir, "yarn.lock"))) {
934
- pm = "yarn";
935
- } else if (fs2.existsSync(path2.join(targetDir, "bun.lockb")) || fs2.existsSync(path2.join(targetDir, "bun.lock"))) {
936
- pm = "bun";
937
- }
938
- }
939
- } catch {
940
- }
941
- const command = `${pm} install`;
942
- if (options?.dryRun) {
943
- return { packageManager: pm, command, skipped: false };
944
- }
945
- try {
946
- console.log(`
947
- [lumenflow init] Installing dependencies (${command})...`);
948
- execFileSync2(pm, ["install"], {
949
- cwd: targetDir,
950
- stdio: "inherit"
951
- });
952
- console.log("[lumenflow init] \u2713 Dependencies installed");
953
- return { packageManager: pm, command, skipped: false };
954
- } catch (err) {
955
- const errorMessage = err instanceof Error ? err.message : String(err);
956
- console.warn(`[lumenflow init] \u26A0 ${command} failed: ${errorMessage}`);
957
- console.warn(`[lumenflow init] Run "${command}" manually to install dependencies.`);
958
- return { packageManager: pm, command, skipped: false, error: errorMessage };
959
- }
960
- }
961
- async function scaffoldFullDocs(targetDir, options, result, tokens) {
962
- const wuDir = path2.join(targetDir, tokens.DOCS_WU_DIR_PATH);
963
- const templatesDir = path2.join(targetDir, tokens.DOCS_TEMPLATES_DIR_PATH);
964
- await createDirectory(wuDir, result, targetDir);
965
- await createDirectory(templatesDir, result, targetDir);
966
- await createFile(path2.join(wuDir, ".gitkeep"), "", options.force, result, targetDir);
967
- await createFile(
968
- path2.join(targetDir, tokens.DOCS_BACKLOG_PATH),
969
- BACKLOG_TEMPLATE,
970
- options.force,
971
- result,
972
- targetDir
973
- );
974
- await createFile(
975
- path2.join(targetDir, tokens.DOCS_STATUS_PATH),
976
- STATUS_TEMPLATE,
977
- options.force,
978
- result,
979
- targetDir
980
- );
981
- await createFile(
982
- path2.join(templatesDir, "wu-template.yaml"),
983
- processTemplate(WU_TEMPLATE_YAML, tokens),
984
- options.force,
985
- result,
986
- targetDir
987
- );
988
- await scaffoldAgentOnboardingDocs(targetDir, options, result, tokens);
989
- }
990
- async function scaffoldAgentOnboardingDocs(targetDir, options, result, tokens) {
991
- const onboardingDir = path2.join(targetDir, tokens.DOCS_ONBOARDING_PATH);
992
- await createDirectory(onboardingDir, result, targetDir);
993
- for (const [outputFile, templatePath] of Object.entries(SCAFFOLDED_ONBOARDING_TEMPLATE_PATHS)) {
994
- await createFile(
995
- path2.join(onboardingDir, outputFile),
996
- processTemplate(loadTemplate(templatePath), tokens),
997
- options.force,
998
- result,
999
- targetDir
1000
- );
1001
- }
1002
- }
1003
- async function scaffoldClaudeSkills(targetDir, options, result, tokens) {
1004
- const skillsDir = path2.join(targetDir, ".claude", "skills");
1005
- const wuLifecycleDir = path2.join(skillsDir, "wu-lifecycle");
1006
- await createDirectory(wuLifecycleDir, result, targetDir);
1007
- await createFile(
1008
- path2.join(wuLifecycleDir, "SKILL.md"),
1009
- processTemplate(WU_LIFECYCLE_SKILL_TEMPLATE, tokens),
1010
- options.force,
1011
- result,
1012
- targetDir
1013
- );
1014
- const worktreeDir = path2.join(skillsDir, "worktree-discipline");
1015
- await createDirectory(worktreeDir, result, targetDir);
1016
- await createFile(
1017
- path2.join(worktreeDir, "SKILL.md"),
1018
- processTemplate(WORKTREE_DISCIPLINE_SKILL_TEMPLATE, tokens),
1019
- options.force,
1020
- result,
1021
- targetDir
1022
- );
1023
- const gatesDir = path2.join(skillsDir, "lumenflow-gates");
1024
- await createDirectory(gatesDir, result, targetDir);
1025
- await createFile(
1026
- path2.join(gatesDir, "SKILL.md"),
1027
- processTemplate(LUMENFLOW_GATES_SKILL_TEMPLATE, tokens),
1028
- options.force,
1029
- result,
1030
- targetDir
1031
- );
1032
- }
1033
- async function scaffoldFrameworkOverlay(targetDir, options, result, tokens) {
1034
- if (!options.framework) {
1035
- return;
1036
- }
1037
- const { name, slug } = normalizeFrameworkName(options.framework);
1038
- const frameworkTokens = {
1039
- ...tokens,
1040
- FRAMEWORK_NAME: name,
1041
- FRAMEWORK_SLUG: slug
1042
- };
1043
- await createFile(
1044
- path2.join(targetDir, FRAMEWORK_HINT_FILE),
1045
- processTemplate(FRAMEWORK_HINT_TEMPLATE, frameworkTokens),
1046
- options.force,
1047
- result,
1048
- targetDir
1049
- );
1050
- const overlayDir = path2.join(targetDir, tokens.DOCS_OPERATIONS_PATH, "_frameworks", slug);
1051
- await createDirectory(overlayDir, result, targetDir);
1052
- await createFile(
1053
- path2.join(overlayDir, "README.md"),
1054
- processTemplate(FRAMEWORK_OVERLAY_TEMPLATE, frameworkTokens),
1055
- options.force,
1056
- result,
1057
- targetDir
1058
- );
1059
- }
1060
- async function scaffoldClientFiles(targetDir, options, result, tokens, client) {
1061
- const fileMode = getFileMode(options);
1062
- if (client === "claude" || client === "all") {
1063
- await createFile(
1064
- path2.join(targetDir, "CLAUDE.md"),
1065
- processTemplate(CLAUDE_MD_TEMPLATE, tokens),
1066
- fileMode,
1067
- result,
1068
- targetDir
1069
- );
1070
- await createDirectory(path2.join(targetDir, CLAUDE_AGENTS_DIR), result, targetDir);
1071
- await createFile(
1072
- path2.join(targetDir, CLAUDE_AGENTS_DIR, ".gitkeep"),
1073
- "",
1074
- options.force ? "force" : "skip",
1075
- result,
1076
- targetDir
1077
- );
1078
- let settingsContent;
1079
- try {
1080
- settingsContent = loadTemplate(CLAUDE_HOOKS.TEMPLATES.SETTINGS);
1081
- } catch {
1082
- settingsContent = CLAUDE_SETTINGS_TEMPLATE;
1083
- }
1084
- await createFile(
1085
- path2.join(targetDir, CLAUDE_DIR, "settings.json"),
1086
- settingsContent,
1087
- options.force ? "force" : "skip",
1088
- result,
1089
- targetDir
1090
- );
1091
- let mcpJsonContent;
1092
- try {
1093
- mcpJsonContent = loadTemplate("core/.mcp.json.template");
1094
- } catch {
1095
- mcpJsonContent = MCP_JSON_TEMPLATE;
1096
- }
1097
- await createFile(
1098
- path2.join(targetDir, ".mcp.json"),
1099
- mcpJsonContent,
1100
- fileMode,
1101
- result,
1102
- targetDir
1103
- );
1104
- const hooksDir = path2.join(targetDir, CLAUDE_DIR, "hooks");
1105
- await createDirectory(hooksDir, result, targetDir);
1106
- try {
1107
- const preCompactScript = loadTemplate(CLAUDE_HOOKS.TEMPLATES.PRE_COMPACT);
1108
- await createExecutableScript(
1109
- path2.join(hooksDir, CLAUDE_HOOKS.SCRIPTS.PRE_COMPACT_CHECKPOINT),
1110
- preCompactScript,
1111
- options.force ? "force" : "skip",
1112
- result,
1113
- targetDir
1114
- );
1115
- } catch {
1116
- }
1117
- const sessionStartScript = generateSessionStartRecoveryScript();
1118
- await createExecutableScript(
1119
- path2.join(hooksDir, CLAUDE_HOOKS.SCRIPTS.SESSION_START_RECOVERY),
1120
- sessionStartScript,
1121
- options.force ? "force" : "skip",
1122
- result,
1123
- targetDir
1124
- );
1125
- await scaffoldClaudeSkills(targetDir, options, result, tokens);
1126
- if (!options.full) {
1127
- await scaffoldAgentOnboardingDocs(targetDir, options, result, tokens);
1128
- }
1129
- }
1130
- if (client === "cursor" || client === "all") {
1131
- const cursorRulesDir = path2.join(targetDir, ".cursor", "rules");
1132
- await createDirectory(cursorRulesDir, result, targetDir);
1133
- let cursorContent;
1134
- try {
1135
- cursorContent = loadTemplate("vendors/cursor/.cursor/rules/lumenflow.md.template");
1136
- } catch {
1137
- cursorContent = CURSOR_RULES_TEMPLATE;
1138
- }
1139
- await createFile(
1140
- path2.join(cursorRulesDir, "lumenflow.md"),
1141
- processTemplate(cursorContent, tokens),
1142
- fileMode,
1143
- result,
1144
- targetDir
1145
- );
1146
- }
1147
- if (client === "windsurf" || client === "all") {
1148
- const windsurfRulesDir = path2.join(targetDir, ".windsurf", "rules");
1149
- await createDirectory(windsurfRulesDir, result, targetDir);
1150
- let windsurfContent;
1151
- try {
1152
- windsurfContent = loadTemplate("vendors/windsurf/.windsurf/rules/lumenflow.md.template");
1153
- } catch {
1154
- windsurfContent = WINDSURF_RULES_TEMPLATE;
1155
- }
1156
- await createFile(
1157
- path2.join(windsurfRulesDir, "lumenflow.md"),
1158
- processTemplate(windsurfContent, tokens),
1159
- fileMode,
1160
- result,
1161
- targetDir
1162
- );
1163
- }
1164
- if (client === "cline" || client === "all") {
1165
- let clineContent;
1166
- try {
1167
- clineContent = loadTemplate("vendors/cline/.clinerules.template");
1168
- } catch {
1169
- clineContent = CLINE_RULES_TEMPLATE;
1170
- }
1171
- await createFile(
1172
- path2.join(targetDir, ".clinerules"),
1173
- processTemplate(clineContent, tokens),
1174
- fileMode,
1175
- result,
1176
- targetDir
1177
- );
1178
- }
1179
- if (client === "aider" || client === "all") {
1180
- await createFile(
1181
- path2.join(targetDir, ".aider.conf.yml"),
1182
- AIDER_CONF_TEMPLATE,
1183
- fileMode,
1184
- result,
1185
- targetDir
1186
- );
1187
- }
1188
- }
1189
- function resolveBootstrapProjectName(targetDir) {
1190
- const basename2 = path2.basename(path2.resolve(targetDir)).trim();
1191
- return basename2.length > 0 ? basename2 : DEFAULT_PROJECT_NAME;
1192
- }
1193
- async function runInitBootstrap(options) {
1194
- if (options.skipBootstrap) {
1195
- return {
1196
- skipped: true,
1197
- reason: BOOTSTRAP_SKIP_REASON_FLAG,
1198
- workspaceGenerated: false,
1199
- packInstalled: false
1200
- };
1201
- }
1202
- const workspacePath = path2.join(options.targetDir, WORKSPACE_FILENAME);
1203
- const hasExistingWorkspace = fs2.existsSync(workspacePath);
1204
- if (hasExistingWorkspace && !options.force) {
1205
- return {
1206
- skipped: true,
1207
- reason: BOOTSTRAP_SKIP_REASON_EXISTING_WORKSPACE,
1208
- workspaceGenerated: false,
1209
- packInstalled: false
1210
- };
1211
- }
1212
- const onboardModule = await import("./onboard.js");
1213
- const onboardResult = await onboardModule.runOnboard({
1214
- targetDir: options.targetDir,
1215
- nonInteractive: true,
1216
- projectName: resolveBootstrapProjectName(options.targetDir),
1217
- domain: options.bootstrapDomain,
1218
- force: options.force,
1219
- skipPackInstall: options.skipBootstrapPackInstall,
1220
- skipDashboard: true,
1221
- fetchFn: options.fetchFn ?? globalThis.fetch
1222
- });
1223
- if (!onboardResult.success) {
1224
- const failureReason = onboardResult.errors.join("; ") || "unknown onboarding error";
1225
- throw createError(ErrorCodes.ONBOARD_FAILED, `${BOOTSTRAP_ERROR_PREFIX} ${failureReason}`);
1226
- }
1227
- const packFailed = !options.skipBootstrapPackInstall && options.bootstrapDomain !== BOOTSTRAP_CUSTOM_DOMAIN && onboardResult.packInstalled !== true;
1228
- const warning = packFailed ? `${BOOTSTRAP_ERROR_PREFIX} failed to install ${options.bootstrapDomain} pack with integrity metadata. Continuing without pack. Retry later with: pnpm pack:install --id ${options.bootstrapDomain}` : void 0;
1229
- if (warning) {
1230
- console.warn(`
1231
- \u26A0 ${warning}
1232
- `);
1233
- }
1234
- return {
1235
- skipped: false,
1236
- workspaceGenerated: onboardResult.workspaceGenerated === true,
1237
- packInstalled: onboardResult.packInstalled === true,
1238
- warning
1239
- };
1240
- }
1241
- async function main() {
1242
- const invokedBinary = path2.basename(process.argv[1] ?? "", ".js");
1243
- const subcommand = process.argv[2];
1244
- if (invokedBinary === CLOUD_CONNECT_BIN) {
1245
- const { runCloudConnectCli } = await import("./onboard.js");
1246
- await runCloudConnectCli();
1247
- return;
1248
- }
1249
- if (subcommand === INIT_SUBCOMMANDS.COMMANDS) {
1250
- const { main: commandsMain } = await import("./commands.js");
1251
- process.argv.splice(2, 1);
1252
- await commandsMain();
1253
- return;
1254
- }
1255
- if (subcommand === LEGACY_SUBCOMMANDS.ONBOARD || subcommand === LEGACY_SUBCOMMANDS.WORKSPACE_INIT_COLON || subcommand === LEGACY_SUBCOMMANDS.WORKSPACE_INIT_DASH) {
1256
- throw createError(
1257
- ErrorCodes.DEPRECATED_API,
1258
- `${LEGACY_SUBCOMMAND_ERROR_PREFIX} "${subcommand}". ${LEGACY_SUBCOMMAND_GUIDANCE}. ${LEGACY_SUBCOMMAND_HELP_HINT}.`
1259
- );
1260
- }
1261
- if (subcommand === INIT_SUBCOMMANDS.CLOUD) {
1262
- const cloudSubcommand = process.argv[3];
1263
- if (cloudSubcommand !== CLOUD_SUBCOMMANDS.CONNECT) {
1264
- throw createError(
1265
- ErrorCodes.INVALID_ARGUMENT,
1266
- `${INIT_ERROR_PREFIX} Unknown cloud subcommand "${cloudSubcommand ?? ""}". ${INIT_CLOUD_CONNECT_HELP}`
1267
- );
1268
- }
1269
- const { runCloudConnectCli } = await import("./onboard.js");
1270
- process.argv.splice(2, 2);
1271
- await runCloudConnectCli();
1272
- return;
1273
- }
1274
- const opts = parseInitOptions();
1275
- const targetDir = process.cwd();
1276
- console.log("[lumenflow init] Scaffolding LumenFlow project...");
1277
- console.log(` Mode: ${opts.full ? "full" : "minimal"}${opts.merge ? " (merge)" : ""}`);
1278
- console.log(` Framework: ${opts.framework ?? "none"}`);
1279
- console.log(` Client: ${opts.client ?? "auto"}`);
1280
- console.log(` Gate preset: ${opts.preset ?? "none (manual config)"}`);
1281
- console.log(` Bootstrap domain: ${opts.bootstrapDomain}`);
1282
- console.log(
1283
- ` Bootstrap pack install: ${opts.skipBootstrapPackInstall ? "skipped (--skip-bootstrap-pack-install)" : "required"}`
1284
- );
1285
- const bootstrapResult = await runInitBootstrap({
1286
- targetDir,
1287
- force: opts.force,
1288
- bootstrapDomain: opts.bootstrapDomain,
1289
- skipBootstrap: opts.skipBootstrap,
1290
- skipBootstrapPackInstall: opts.skipBootstrapPackInstall
1291
- });
1292
- if (bootstrapResult.skipped) {
1293
- console.log(` Bootstrap: skipped (${bootstrapResult.reason})`);
1294
- } else {
1295
- console.log(
1296
- ` Bootstrap: workspace=${bootstrapResult.workspaceGenerated ? "created" : "unchanged"}, pack=${bootstrapResult.packInstalled ? "installed" : "skipped"}`
1297
- );
1298
- }
1299
- const result = await scaffoldProject(targetDir, {
1300
- force: opts.force,
1301
- full: opts.full,
1302
- merge: opts.merge,
1303
- client: opts.client,
1304
- vendor: opts.vendor,
1305
- // Backwards compatibility
1306
- framework: opts.framework,
1307
- gatePreset: opts.preset
1308
- });
1309
- if (result.created.length > 0) {
1310
- console.log("\nCreated:");
1311
- result.created.forEach((f) => console.log(` + ${f}`));
1312
- }
1313
- if (result.merged && result.merged.length > 0) {
1314
- console.log("\nMerged (LumenFlow block inserted/updated):");
1315
- result.merged.forEach((f) => console.log(` ~ ${f}`));
1316
- }
1317
- if (result.overwritten && result.overwritten.length > 0) {
1318
- console.log("\nOverwritten (existing file replaced with --force):");
1319
- result.overwritten.forEach((f) => console.log(` ! ${f}`));
1320
- }
1321
- if (result.skipped.length > 0) {
1322
- console.log("\nSkipped (already exists, use --force to overwrite or --merge to insert block):");
1323
- result.skipped.forEach((f) => console.log(` - ${f}`));
1324
- }
1325
- if (result.warnings && result.warnings.length > 0) {
1326
- console.log("\nWarnings:");
1327
- result.warnings.forEach((w) => console.log(` \u26A0 ${w}`));
1328
- }
1329
- await runPostScaffoldInstall(targetDir);
1330
- try {
1331
- const doctorResult = await runDoctorForInit(targetDir);
1332
- if (doctorResult.output) {
1333
- console.log("");
1334
- console.log(doctorResult.output);
1335
- }
1336
- } catch {
1337
- }
1338
- console.log("\n[lumenflow init] Done! Next steps:");
1339
- console.log(" 1. Review AGENTS.md and LUMENFLOW.md for workflow documentation");
1340
- console.log(
1341
- ` 2. Review ${CONFIG_FILE_NAME} ${SOFTWARE_DELIVERY_KEY} settings for project defaults`
1342
- );
1343
- console.log("");
1344
- console.log(` ${buildInitLaneLifecycleMessage(LANE_LIFECYCLE_STATUS.UNCONFIGURED)}`);
1345
- if (result.integrationFiles && result.integrationFiles.length > 0) {
1346
- console.log(
1347
- " \u2713 Enforcement hooks installed -- regenerate with: pnpm lumenflow:integrate"
1348
- );
1349
- }
1350
- console.log("");
1351
- console.log(" For a product vision (multi-phase work):");
1352
- console.log(' pnpm initiative:create --id INIT-001 --title "Project Name" \\');
1353
- console.log(' --phase "Phase 1: MVP" --phase "Phase 2: Polish"');
1354
- console.log("");
1355
- console.log(" For a single WU:");
1356
- console.log(' pnpm wu:create --lane <lane> --title "First WU" \\');
1357
- console.log(' --description "Context: ... Problem: ... Solution: ..." \\');
1358
- console.log(' --acceptance "Criterion 1" --code-paths "src/..." --exposure backend-only');
1359
- console.log("");
1360
- console.log(" # Or for rapid prototyping (minimal validation):");
1361
- console.log(' pnpm wu:proto --lane <lane> --title "Quick experiment"');
1362
- console.log("");
1363
- console.log(" Full lifecycle: wu:create -> wu:claim -> wu:prep -> wu:done");
1364
- }
1365
- if (import.meta.main) {
1366
- void runCLI(main, { showHeader: true });
1367
- }
1368
-
1369
- export {
1370
- detectIDEEnvironment,
1371
- checkPrerequisites,
1372
- getDocsPath,
1373
- detectDocsStructure,
1374
- parseInitOptions,
1375
- renameMasterToMainIfNeeded,
1376
- scaffoldProject,
1377
- runPostScaffoldInstall,
1378
- runInitBootstrap,
1379
- main
1380
- };