@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.
- package/README.md +36 -35
- package/dist/agent-issues-query.js +13 -8
- package/dist/agent-log-issue.js +15 -4
- package/dist/agent-session-end.js +15 -4
- package/dist/agent-session.js +18 -6
- package/dist/backlog-prune.js +1 -1
- package/dist/commands/integrate.js +32 -18
- package/dist/config-get.js +27 -15
- package/dist/config-set.js +104 -37
- package/dist/delegation-list.js +1 -1
- package/dist/doctor.js +19 -13
- package/dist/file-delete.js +1 -1
- package/dist/file-edit.js +1 -1
- package/dist/file-read.js +1 -1
- package/dist/file-write.js +1 -1
- package/dist/flow-bottlenecks.js +1 -1
- package/dist/flow-report.js +10 -9
- package/dist/gates.js +3 -2
- package/dist/git-branch.js +1 -1
- package/dist/git-diff.js +1 -1
- package/dist/git-log.js +1 -1
- package/dist/init.js +238 -42
- package/dist/initiative-add-wu.js +1 -1
- package/dist/initiative-bulk-assign-wus.js +1 -1
- package/dist/initiative-create.js +2 -2
- package/dist/initiative-edit.js +1 -1
- package/dist/initiative-list.js +1 -1
- package/dist/initiative-plan.js +1 -3
- package/dist/initiative-status.js +47 -6
- package/dist/lane-edit.js +19 -10
- package/dist/lane-health.js +13 -24
- package/dist/lane-lock.js +4 -5
- package/dist/lane-setup.js +5 -5
- package/dist/lane-status.js +4 -5
- package/dist/lane-suggest.js +9 -7
- package/dist/lane-validate.js +4 -5
- package/dist/lumenflow-upgrade.js +17 -11
- package/dist/mem-checkpoint.js +1 -1
- package/dist/mem-cleanup.js +6 -23
- package/dist/mem-context.js +1 -1
- package/dist/mem-create.js +1 -1
- package/dist/mem-delete.js +1 -1
- package/dist/mem-export.js +1 -1
- package/dist/mem-inbox.js +1 -1
- package/dist/mem-init.js +1 -1
- package/dist/mem-ready.js +1 -1
- package/dist/mem-recover.js +1 -1
- package/dist/mem-signal.js +1 -1
- package/dist/mem-start.js +1 -1
- package/dist/mem-summarize.js +8 -7
- package/dist/mem-triage.js +7 -5
- package/dist/metrics-cli.js +1 -1
- package/dist/metrics-snapshot.js +1 -1
- package/dist/onboard.js +295 -120
- package/dist/orchestrate-init-status.js +12 -7
- package/dist/orchestrate-initiative.js +23 -12
- package/dist/orchestrate-monitor.js +20 -8
- package/dist/pack-scaffold.js +1 -1
- package/dist/plan-create.js +1 -3
- package/dist/plan-edit.js +1 -3
- package/dist/plan-link.js +1 -3
- package/dist/plan-promote.js +1 -3
- package/dist/release.js +1 -3
- package/dist/signal-cleanup.js +4 -18
- package/dist/state-bootstrap.js +11 -8
- package/dist/state-cleanup.js +5 -19
- package/dist/state-doctor.js +213 -9
- package/dist/task-claim.js +1 -1
- package/dist/validate.js +1 -1
- package/dist/workspace-init.js +61 -61
- package/dist/wu-block.js +1 -1
- package/dist/wu-brief.js +1 -1
- package/dist/wu-claim.js +1 -1
- package/dist/wu-cleanup.js +1 -1
- package/dist/wu-create.js +3 -3
- package/dist/wu-delegate.js +1 -1
- package/dist/wu-deps.js +1 -1
- package/dist/wu-done.js +66 -34
- package/dist/wu-edit.js +1 -1
- package/dist/wu-infer-lane.js +1 -1
- package/dist/wu-preflight.js +1 -1
- package/dist/wu-prep.js +1 -1
- package/dist/wu-proto.js +1 -1
- package/dist/wu-prune.js +1 -1
- package/dist/wu-recover.js +1 -1
- package/dist/wu-release.js +1 -1
- package/dist/wu-repair.js +1 -1
- package/dist/wu-sandbox.js +40 -27
- package/dist/wu-status.js +1 -1
- package/dist/wu-unblock.js +1 -1
- package/dist/wu-unlock-lane.js +1 -1
- package/dist/wu-validate.js +1 -1
- package/package.json +12 -8
- package/packs/software-delivery/constants.ts +10 -0
- package/packs/software-delivery/extensions.ts +140 -0
- package/packs/software-delivery/gate-policies.ts +134 -0
- package/packs/software-delivery/index.ts +8 -0
- package/packs/software-delivery/manifest-schema.ts +236 -0
- package/packs/software-delivery/manifest.ts +417 -0
- package/packs/software-delivery/manifest.yaml +711 -0
- package/packs/software-delivery/pack-registration.ts +113 -0
- package/packs/software-delivery/tool-impl/agent-tools.ts +263 -0
- package/packs/software-delivery/tool-impl/delegation-tools.ts +66 -0
- package/packs/software-delivery/tool-impl/flow-metrics-tools.ts +219 -0
- package/packs/software-delivery/tool-impl/git-runner.ts +113 -0
- package/packs/software-delivery/tool-impl/git-tools.ts +316 -0
- package/packs/software-delivery/tool-impl/index.ts +15 -0
- package/packs/software-delivery/tool-impl/initiative-orchestration-tools.ts +720 -0
- package/packs/software-delivery/tool-impl/lane-lock.ts +246 -0
- package/packs/software-delivery/tool-impl/memory-tools.ts +415 -0
- package/packs/software-delivery/tool-impl/pending-runtime-tools.ts +21 -0
- package/packs/software-delivery/tool-impl/runtime-cli-adapter.ts +328 -0
- package/packs/software-delivery/tool-impl/runtime-native-tools.ts +687 -0
- package/packs/software-delivery/tool-impl/worker-loader.ts +52 -0
- package/packs/software-delivery/tool-impl/worktree-tools.ts +46 -0
- package/packs/software-delivery/tool-impl/wu-lifecycle-tools.ts +759 -0
- package/packs/software-delivery/tools/delegation-tools.ts +23 -0
- package/packs/software-delivery/tools/git-tools.ts +55 -0
- package/packs/software-delivery/tools/index.ts +8 -0
- package/packs/software-delivery/tools/lane-lock-tool.ts +37 -0
- package/packs/software-delivery/tools/types.ts +71 -0
- package/packs/software-delivery/tools/worktree-tools.ts +49 -0
- package/templates/core/LUMENFLOW.md.template +3 -3
- package/templates/core/ai/onboarding/agent-invocation-guide.md.template +1 -1
- package/templates/core/ai/onboarding/lumenflow-force-usage.md.template +1 -1
- package/templates/core/ai/onboarding/quick-ref-commands.md.template +5 -5
- package/templates/core/ai/onboarding/starting-prompt.md.template +3 -3
- package/templates/core/ai/onboarding/vendor-support.md.template +1 -1
- package/templates/core/ai/onboarding/wu-create-checklist.md.template +1 -1
- package/dist/agent-issues-query.js.map +0 -1
- package/dist/agent-log-issue.js.map +0 -1
- package/dist/agent-session-end.js.map +0 -1
- package/dist/agent-session.js.map +0 -1
- package/dist/backlog-prune.js.map +0 -1
- package/dist/cli-entry-point.js +0 -149
- package/dist/cli-entry-point.js.map +0 -1
- package/dist/commands/integrate.js.map +0 -1
- package/dist/commands.js.map +0 -1
- package/dist/config-get.js.map +0 -1
- package/dist/config-set.js.map +0 -1
- package/dist/delegation-list.js.map +0 -1
- package/dist/deps-add.js +0 -259
- package/dist/deps-add.js.map +0 -1
- package/dist/deps-remove.js +0 -105
- package/dist/deps-remove.js.map +0 -1
- package/dist/docs-sync.js.map +0 -1
- package/dist/doctor.js.map +0 -1
- package/dist/file-delete.js.map +0 -1
- package/dist/file-edit.js.map +0 -1
- package/dist/file-read.js.map +0 -1
- package/dist/file-write.js.map +0 -1
- package/dist/flow-bottlenecks.js.map +0 -1
- package/dist/flow-report.js.map +0 -1
- package/dist/formatters.js +0 -151
- package/dist/formatters.js.map +0 -1
- package/dist/gate-defaults.js +0 -131
- package/dist/gate-defaults.js.map +0 -1
- package/dist/gate-registry.js +0 -73
- package/dist/gate-registry.js.map +0 -1
- package/dist/gates-graceful-degradation.js +0 -153
- package/dist/gates-graceful-degradation.js.map +0 -1
- package/dist/gates-plan-resolvers.js +0 -152
- package/dist/gates-plan-resolvers.js.map +0 -1
- package/dist/gates-runners.js +0 -509
- package/dist/gates-runners.js.map +0 -1
- package/dist/gates-types.js +0 -4
- package/dist/gates-types.js.map +0 -1
- package/dist/gates-utils.js +0 -323
- package/dist/gates-utils.js.map +0 -1
- package/dist/gates.js.map +0 -1
- package/dist/git-branch.js.map +0 -1
- package/dist/git-diff.js.map +0 -1
- package/dist/git-log.js.map +0 -1
- package/dist/git-status.js.map +0 -1
- package/dist/guard-locked.js +0 -172
- package/dist/guard-locked.js.map +0 -1
- package/dist/guard-main-branch.js +0 -217
- package/dist/guard-main-branch.js.map +0 -1
- package/dist/guard-worktree-commit.js +0 -163
- package/dist/guard-worktree-commit.js.map +0 -1
- package/dist/hooks/auto-checkpoint-utils.js +0 -54
- package/dist/hooks/auto-checkpoint-utils.js.map +0 -1
- package/dist/hooks/enforcement-checks.js +0 -399
- package/dist/hooks/enforcement-checks.js.map +0 -1
- package/dist/hooks/enforcement-generator.js +0 -139
- package/dist/hooks/enforcement-generator.js.map +0 -1
- package/dist/hooks/enforcement-sync.js +0 -385
- package/dist/hooks/enforcement-sync.js.map +0 -1
- package/dist/hooks/generators/auto-checkpoint.js +0 -125
- package/dist/hooks/generators/auto-checkpoint.js.map +0 -1
- package/dist/hooks/generators/enforce-worktree.js +0 -190
- package/dist/hooks/generators/enforce-worktree.js.map +0 -1
- package/dist/hooks/generators/index.js +0 -18
- package/dist/hooks/generators/index.js.map +0 -1
- package/dist/hooks/generators/pre-compact-checkpoint.js +0 -136
- package/dist/hooks/generators/pre-compact-checkpoint.js.map +0 -1
- package/dist/hooks/generators/require-wu.js +0 -117
- package/dist/hooks/generators/require-wu.js.map +0 -1
- package/dist/hooks/generators/session-start-recovery.js +0 -103
- package/dist/hooks/generators/session-start-recovery.js.map +0 -1
- package/dist/hooks/generators/signal-utils.js +0 -54
- package/dist/hooks/generators/signal-utils.js.map +0 -1
- package/dist/hooks/generators/warn-incomplete.js +0 -67
- package/dist/hooks/generators/warn-incomplete.js.map +0 -1
- package/dist/hooks/index.js +0 -10
- package/dist/hooks/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init-detection.js +0 -232
- package/dist/init-detection.js.map +0 -1
- package/dist/init-lane-validation.js +0 -143
- package/dist/init-lane-validation.js.map +0 -1
- package/dist/init-scaffolding.js +0 -158
- package/dist/init-scaffolding.js.map +0 -1
- package/dist/init-templates.js +0 -1982
- package/dist/init-templates.js.map +0 -1
- package/dist/init.js.map +0 -1
- package/dist/initiative-add-wu.js.map +0 -1
- package/dist/initiative-bulk-assign-wus.js.map +0 -1
- package/dist/initiative-create.js.map +0 -1
- package/dist/initiative-edit.js.map +0 -1
- package/dist/initiative-list.js.map +0 -1
- package/dist/initiative-plan.js.map +0 -1
- package/dist/initiative-remove-wu.js.map +0 -1
- package/dist/initiative-status.js.map +0 -1
- package/dist/lane-edit.js.map +0 -1
- package/dist/lane-health.js.map +0 -1
- package/dist/lane-lifecycle-process.js +0 -366
- package/dist/lane-lifecycle-process.js.map +0 -1
- package/dist/lane-lock.js.map +0 -1
- package/dist/lane-setup.js.map +0 -1
- package/dist/lane-status.js.map +0 -1
- package/dist/lane-suggest.js.map +0 -1
- package/dist/lane-validate.js.map +0 -1
- package/dist/lifecycle-regression-harness.js +0 -181
- package/dist/lifecycle-regression-harness.js.map +0 -1
- package/dist/lumenflow-upgrade.js.map +0 -1
- package/dist/mem-checkpoint.js.map +0 -1
- package/dist/mem-cleanup.js.map +0 -1
- package/dist/mem-context.js.map +0 -1
- package/dist/mem-create.js.map +0 -1
- package/dist/mem-delete.js.map +0 -1
- package/dist/mem-export.js.map +0 -1
- package/dist/mem-inbox.js.map +0 -1
- package/dist/mem-index.js +0 -214
- package/dist/mem-index.js.map +0 -1
- package/dist/mem-init.js.map +0 -1
- package/dist/mem-profile.js +0 -210
- package/dist/mem-profile.js.map +0 -1
- package/dist/mem-promote.js +0 -257
- package/dist/mem-promote.js.map +0 -1
- package/dist/mem-ready.js.map +0 -1
- package/dist/mem-recover.js.map +0 -1
- package/dist/mem-signal.js.map +0 -1
- package/dist/mem-start.js.map +0 -1
- package/dist/mem-summarize.js.map +0 -1
- package/dist/mem-triage.js.map +0 -1
- package/dist/merge-block.js +0 -225
- package/dist/merge-block.js.map +0 -1
- package/dist/metrics-cli.js.map +0 -1
- package/dist/metrics-snapshot.js.map +0 -1
- package/dist/onboard.js.map +0 -1
- package/dist/onboarding-smoke-test.js +0 -418
- package/dist/onboarding-smoke-test.js.map +0 -1
- package/dist/orchestrate-init-status.js.map +0 -1
- package/dist/orchestrate-initiative.js.map +0 -1
- package/dist/orchestrate-monitor.js.map +0 -1
- package/dist/pack-author.js.map +0 -1
- package/dist/pack-hash.js.map +0 -1
- package/dist/pack-install.js.map +0 -1
- package/dist/pack-publish.js.map +0 -1
- package/dist/pack-scaffold.js.map +0 -1
- package/dist/pack-search.js.map +0 -1
- package/dist/pack-validate.js.map +0 -1
- package/dist/plan-create.js.map +0 -1
- package/dist/plan-edit.js.map +0 -1
- package/dist/plan-link.js.map +0 -1
- package/dist/plan-promote.js.map +0 -1
- package/dist/public-manifest.js +0 -920
- package/dist/public-manifest.js.map +0 -1
- package/dist/release.js.map +0 -1
- package/dist/rotate-progress.js +0 -253
- package/dist/rotate-progress.js.map +0 -1
- package/dist/session-coordinator.js +0 -303
- package/dist/session-coordinator.js.map +0 -1
- package/dist/shared-validators.js +0 -81
- package/dist/shared-validators.js.map +0 -1
- package/dist/signal-cleanup.js.map +0 -1
- package/dist/state-bootstrap.js.map +0 -1
- package/dist/state-cleanup.js.map +0 -1
- package/dist/state-doctor-fix.js +0 -226
- package/dist/state-doctor-fix.js.map +0 -1
- package/dist/state-doctor-stamps.js +0 -23
- package/dist/state-doctor-stamps.js.map +0 -1
- package/dist/state-doctor.js.map +0 -1
- package/dist/strict-progress.js +0 -255
- package/dist/strict-progress.js.map +0 -1
- package/dist/sync-templates.js.map +0 -1
- package/dist/task-claim.js.map +0 -1
- package/dist/trace-gen.js +0 -401
- package/dist/trace-gen.js.map +0 -1
- package/dist/validate-agent-skills.js +0 -223
- package/dist/validate-agent-skills.js.map +0 -1
- package/dist/validate-agent-sync.js +0 -151
- package/dist/validate-agent-sync.js.map +0 -1
- package/dist/validate-backlog-sync.js +0 -77
- package/dist/validate-backlog-sync.js.map +0 -1
- package/dist/validate-skills-spec.js +0 -211
- package/dist/validate-skills-spec.js.map +0 -1
- package/dist/validate.js.map +0 -1
- package/dist/validator-defaults.js +0 -107
- package/dist/validator-defaults.js.map +0 -1
- package/dist/validator-registry.js +0 -71
- package/dist/validator-registry.js.map +0 -1
- package/dist/workspace-init.js.map +0 -1
- package/dist/wu-block.js.map +0 -1
- package/dist/wu-brief.js.map +0 -1
- package/dist/wu-claim-branch.js +0 -123
- package/dist/wu-claim-branch.js.map +0 -1
- package/dist/wu-claim-cloud.js +0 -79
- package/dist/wu-claim-cloud.js.map +0 -1
- package/dist/wu-claim-mode.js +0 -82
- package/dist/wu-claim-mode.js.map +0 -1
- package/dist/wu-claim-output.js +0 -85
- package/dist/wu-claim-output.js.map +0 -1
- package/dist/wu-claim-repair-guidance.js +0 -12
- package/dist/wu-claim-repair-guidance.js.map +0 -1
- package/dist/wu-claim-resume-handler.js +0 -87
- package/dist/wu-claim-resume-handler.js.map +0 -1
- package/dist/wu-claim-state.js +0 -581
- package/dist/wu-claim-state.js.map +0 -1
- package/dist/wu-claim-validation.js +0 -457
- package/dist/wu-claim-validation.js.map +0 -1
- package/dist/wu-claim-worktree.js +0 -223
- package/dist/wu-claim-worktree.js.map +0 -1
- package/dist/wu-claim.js.map +0 -1
- package/dist/wu-cleanup-cloud.js +0 -78
- package/dist/wu-cleanup-cloud.js.map +0 -1
- package/dist/wu-cleanup.js.map +0 -1
- package/dist/wu-code-path-coverage.js +0 -83
- package/dist/wu-code-path-coverage.js.map +0 -1
- package/dist/wu-create-cloud.js +0 -30
- package/dist/wu-create-cloud.js.map +0 -1
- package/dist/wu-create-content.js +0 -264
- package/dist/wu-create-content.js.map +0 -1
- package/dist/wu-create-readiness.js +0 -59
- package/dist/wu-create-readiness.js.map +0 -1
- package/dist/wu-create-validation.js +0 -128
- package/dist/wu-create-validation.js.map +0 -1
- package/dist/wu-create.js.map +0 -1
- package/dist/wu-delegate.js.map +0 -1
- package/dist/wu-delete.js.map +0 -1
- package/dist/wu-deps.js.map +0 -1
- package/dist/wu-done-auto-cleanup.js +0 -203
- package/dist/wu-done-auto-cleanup.js.map +0 -1
- package/dist/wu-done-check.js +0 -38
- package/dist/wu-done-check.js.map +0 -1
- package/dist/wu-done-cloud.js +0 -48
- package/dist/wu-done-cloud.js.map +0 -1
- package/dist/wu-done-decay.js +0 -86
- package/dist/wu-done-decay.js.map +0 -1
- package/dist/wu-done.js.map +0 -1
- package/dist/wu-edit-operations.js +0 -399
- package/dist/wu-edit-operations.js.map +0 -1
- package/dist/wu-edit-validators.js +0 -282
- package/dist/wu-edit-validators.js.map +0 -1
- package/dist/wu-edit.js.map +0 -1
- package/dist/wu-infer-lane.js.map +0 -1
- package/dist/wu-preflight.js.map +0 -1
- package/dist/wu-prep.js.map +0 -1
- package/dist/wu-proto.js.map +0 -1
- package/dist/wu-prune.js.map +0 -1
- package/dist/wu-recover.js.map +0 -1
- package/dist/wu-release.js.map +0 -1
- package/dist/wu-repair.js.map +0 -1
- package/dist/wu-sandbox.js.map +0 -1
- package/dist/wu-spawn-completion.js +0 -33
- package/dist/wu-spawn-completion.js.map +0 -1
- package/dist/wu-spawn-prompt-builders.js +0 -1197
- package/dist/wu-spawn-prompt-builders.js.map +0 -1
- package/dist/wu-spawn-strategy-resolver.js +0 -322
- package/dist/wu-spawn-strategy-resolver.js.map +0 -1
- package/dist/wu-spawn.js +0 -59
- package/dist/wu-spawn.js.map +0 -1
- package/dist/wu-state-cloud.js +0 -41
- package/dist/wu-state-cloud.js.map +0 -1
- package/dist/wu-status.js.map +0 -1
- package/dist/wu-unblock.js.map +0 -1
- package/dist/wu-unlock-lane.js.map +0 -1
- 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
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
|
498
|
+
let softwareDeliveryConfig;
|
|
385
499
|
try {
|
|
386
500
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
387
|
-
|
|
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 (!
|
|
509
|
+
if (!softwareDeliveryConfig)
|
|
393
510
|
return integrationFiles;
|
|
394
|
-
const agents =
|
|
395
|
-
const clients = agents?.
|
|
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,
|
|
399
|
-
const
|
|
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
|
-
//
|
|
508
|
-
|
|
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 (
|
|
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.
|
|
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
|
-
* .
|
|
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)',
|
package/dist/initiative-edit.js
CHANGED
|
@@ -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}`);
|
package/dist/initiative-list.js
CHANGED
|
@@ -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',
|
package/dist/initiative-plan.js
CHANGED
|
@@ -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
|
-
|
|
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(
|
|
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:
|
|
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 .
|
|
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 {
|
|
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 .
|
|
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,
|
|
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 ${
|
|
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
|
|
230
|
-
|
|
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
|
|
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 =
|
|
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}`);
|