@lumenflow/cli 2.1.1 → 2.1.2

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.
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @file guard-main-branch.test.ts
3
+ * @description Tests for guard-main-branch worktree context detection (WU-1130)
4
+ */
5
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
6
+ import { guardMainBranch } from '../guard-main-branch.js';
7
+ // Mock the core module
8
+ vi.mock('@lumenflow/core', () => ({
9
+ createGitForPath: vi.fn(),
10
+ getGitForCwd: vi.fn(),
11
+ isAgentBranch: vi.fn().mockResolvedValue(false),
12
+ getConfig: vi.fn().mockReturnValue({
13
+ git: {
14
+ mainBranch: 'main',
15
+ laneBranchPrefix: 'lane/',
16
+ },
17
+ }),
18
+ }));
19
+ // Mock the worktree-guard module
20
+ vi.mock('@lumenflow/core/dist/core/worktree-guard.js', () => ({
21
+ isInWorktree: vi.fn(),
22
+ }));
23
+ import { getGitForCwd, createGitForPath } from '@lumenflow/core';
24
+ import { isInWorktree } from '@lumenflow/core/dist/core/worktree-guard.js';
25
+ describe('guard-main-branch (WU-1130)', () => {
26
+ beforeEach(() => {
27
+ vi.clearAllMocks();
28
+ });
29
+ afterEach(() => {
30
+ vi.restoreAllMocks();
31
+ });
32
+ describe('lane branch worktree detection', () => {
33
+ it('should allow operations when on lane branch AND in worktree', async () => {
34
+ // Setup: On lane branch, in worktree
35
+ const mockGit = {
36
+ getCurrentBranch: vi.fn().mockResolvedValue('lane/framework-cli/wu-1130'),
37
+ };
38
+ vi.mocked(getGitForCwd).mockReturnValue(mockGit);
39
+ vi.mocked(isInWorktree).mockReturnValue(true);
40
+ const result = await guardMainBranch({});
41
+ expect(result.success).toBe(true);
42
+ expect(result.isProtected).toBe(false);
43
+ expect(result.currentBranch).toBe('lane/framework-cli/wu-1130');
44
+ });
45
+ it('should block operations when on lane branch but NOT in worktree', async () => {
46
+ // Setup: On lane branch, but not in worktree (e.g., checked out directly)
47
+ const mockGit = {
48
+ getCurrentBranch: vi.fn().mockResolvedValue('lane/framework-cli/wu-1130'),
49
+ };
50
+ vi.mocked(getGitForCwd).mockReturnValue(mockGit);
51
+ vi.mocked(isInWorktree).mockReturnValue(false);
52
+ const result = await guardMainBranch({});
53
+ expect(result.success).toBe(true);
54
+ expect(result.isProtected).toBe(true);
55
+ expect(result.reason).toContain('requires worktree');
56
+ });
57
+ it('should use baseDir for worktree detection when provided', async () => {
58
+ const mockGit = {
59
+ getCurrentBranch: vi.fn().mockResolvedValue('lane/ops-tooling/wu-2725'),
60
+ };
61
+ vi.mocked(createGitForPath).mockReturnValue(mockGit);
62
+ vi.mocked(isInWorktree).mockReturnValue(true);
63
+ const result = await guardMainBranch({ baseDir: '/path/to/worktrees/ops-tooling-wu-2725' });
64
+ expect(isInWorktree).toHaveBeenCalledWith({ cwd: '/path/to/worktrees/ops-tooling-wu-2725' });
65
+ expect(result.isProtected).toBe(false);
66
+ });
67
+ });
68
+ describe('main branch protection', () => {
69
+ it('should block operations on main branch', async () => {
70
+ const mockGit = {
71
+ getCurrentBranch: vi.fn().mockResolvedValue('main'),
72
+ };
73
+ vi.mocked(getGitForCwd).mockReturnValue(mockGit);
74
+ const result = await guardMainBranch({});
75
+ expect(result.isProtected).toBe(true);
76
+ expect(result.reason).toContain("'main' is protected");
77
+ });
78
+ });
79
+ });
@@ -13,6 +13,7 @@
13
13
  * WU-1109: INIT-003 Phase 4b - Migrate git operations
14
14
  */
15
15
  import { createGitForPath, getGitForCwd, isAgentBranch, getConfig } from '@lumenflow/core';
16
+ import { isInWorktree } from '@lumenflow/core/dist/core/worktree-guard.js';
16
17
  /**
17
18
  * Parse command line arguments for guard-main-branch
18
19
  */
@@ -90,6 +91,16 @@ export async function guardMainBranch(args) {
90
91
  }
91
92
  // Check if on a lane branch (requires worktree discipline)
92
93
  if (isLaneBranch(currentBranch)) {
94
+ // If we're actually in a worktree, allow the operation (WU-1130)
95
+ const cwd = args.baseDir ?? process.cwd();
96
+ if (isInWorktree({ cwd })) {
97
+ return {
98
+ success: true,
99
+ isProtected: false,
100
+ currentBranch,
101
+ };
102
+ }
103
+ // On lane branch but not in worktree - block
93
104
  return {
94
105
  success: true,
95
106
  isProtected: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumenflow/cli",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "Command-line interface for LumenFlow workflow framework",
5
5
  "keywords": [
6
6
  "lumenflow",
@@ -132,11 +132,11 @@
132
132
  "pretty-ms": "^9.2.0",
133
133
  "simple-git": "^3.30.0",
134
134
  "yaml": "^2.8.2",
135
- "@lumenflow/core": "2.1.1",
136
- "@lumenflow/metrics": "2.1.1",
137
- "@lumenflow/memory": "2.1.1",
138
- "@lumenflow/initiatives": "2.1.1",
139
- "@lumenflow/agent": "2.1.1"
135
+ "@lumenflow/core": "2.1.2",
136
+ "@lumenflow/metrics": "2.1.2",
137
+ "@lumenflow/memory": "2.1.2",
138
+ "@lumenflow/initiatives": "2.1.2",
139
+ "@lumenflow/agent": "2.1.2"
140
140
  },
141
141
  "devDependencies": {
142
142
  "@vitest/coverage-v8": "^4.0.17",