@lumenflow/cli 2.20.1 → 2.21.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/dist/hooks/enforcement-checks.js +120 -0
- package/dist/hooks/enforcement-checks.js.map +1 -1
- package/dist/init-lane-validation.js +141 -0
- package/dist/init-lane-validation.js.map +1 -0
- package/dist/init-templates.js +36 -8
- package/dist/init-templates.js.map +1 -1
- package/dist/init.js +27 -58
- package/dist/init.js.map +1 -1
- package/dist/initiative-create.js +35 -4
- package/dist/initiative-create.js.map +1 -1
- package/dist/lane-lifecycle-process.js +364 -0
- package/dist/lane-lifecycle-process.js.map +1 -0
- package/dist/lane-lock.js +41 -0
- package/dist/lane-lock.js.map +1 -0
- package/dist/lane-setup.js +55 -0
- package/dist/lane-setup.js.map +1 -0
- package/dist/lane-status.js +38 -0
- package/dist/lane-status.js.map +1 -0
- package/dist/lane-validate.js +43 -0
- package/dist/lane-validate.js.map +1 -0
- package/dist/onboarding-smoke-test.js +17 -0
- package/dist/onboarding-smoke-test.js.map +1 -1
- package/dist/public-manifest.js +28 -0
- package/dist/public-manifest.js.map +1 -1
- package/dist/wu-claim-cloud.js +16 -0
- package/dist/wu-claim-cloud.js.map +1 -1
- package/dist/wu-claim.js +12 -2
- package/dist/wu-claim.js.map +1 -1
- package/dist/wu-create-content.js +8 -2
- package/dist/wu-create-content.js.map +1 -1
- package/dist/wu-create-validation.js +5 -3
- package/dist/wu-create-validation.js.map +1 -1
- package/dist/wu-create.js +21 -1
- package/dist/wu-create.js.map +1 -1
- package/dist/wu-done.js +57 -8
- package/dist/wu-done.js.map +1 -1
- package/dist/wu-prep.js +22 -0
- package/dist/wu-prep.js.map +1 -1
- package/package.json +15 -11
- package/dist/__tests__/agent-log-issue.test.js +0 -56
- package/dist/__tests__/agent-spawn-coordination.test.js +0 -451
- package/dist/__tests__/backlog-prune.test.js +0 -478
- package/dist/__tests__/cli-entry-point.test.js +0 -160
- package/dist/__tests__/cli-subprocess.test.js +0 -89
- package/dist/__tests__/commands/integrate.test.js +0 -165
- package/dist/__tests__/commands.test.js +0 -271
- package/dist/__tests__/deps-operations.test.js +0 -206
- package/dist/__tests__/doctor.test.js +0 -510
- package/dist/__tests__/file-operations.test.js +0 -906
- package/dist/__tests__/flow-report.test.js +0 -24
- package/dist/__tests__/gates-config.test.js +0 -303
- package/dist/__tests__/gates-integration-tests.test.js +0 -112
- package/dist/__tests__/git-operations.test.js +0 -668
- package/dist/__tests__/guard-main-branch.test.js +0 -79
- package/dist/__tests__/guards-validation.test.js +0 -416
- package/dist/__tests__/hooks/enforcement.test.js +0 -279
- package/dist/__tests__/init-config-lanes.test.js +0 -131
- package/dist/__tests__/init-docs-structure.test.js +0 -152
- package/dist/__tests__/init-greenfield.test.js +0 -247
- package/dist/__tests__/init-lane-inference.test.js +0 -125
- package/dist/__tests__/init-onboarding-docs.test.js +0 -132
- package/dist/__tests__/init-quick-ref.test.js +0 -144
- package/dist/__tests__/init-scripts.test.js +0 -207
- package/dist/__tests__/init-template-portability.test.js +0 -96
- package/dist/__tests__/init.test.js +0 -968
- package/dist/__tests__/initiative-add-wu.test.js +0 -490
- package/dist/__tests__/initiative-e2e.test.js +0 -442
- package/dist/__tests__/initiative-plan-replacement.test.js +0 -161
- package/dist/__tests__/initiative-plan.test.js +0 -340
- package/dist/__tests__/initiative-remove-wu.test.js +0 -458
- package/dist/__tests__/lumenflow-upgrade.test.js +0 -260
- package/dist/__tests__/mem-cleanup-execution.test.js +0 -19
- package/dist/__tests__/memory-integration.test.js +0 -333
- package/dist/__tests__/merge-block.test.js +0 -220
- package/dist/__tests__/metrics-cli.test.js +0 -619
- package/dist/__tests__/metrics-snapshot.test.js +0 -24
- package/dist/__tests__/no-beacon-references-docs.test.js +0 -30
- package/dist/__tests__/no-beacon-references.test.js +0 -39
- package/dist/__tests__/onboarding-smoke-test.test.js +0 -211
- package/dist/__tests__/path-centralization-cli.test.js +0 -234
- package/dist/__tests__/plan-create.test.js +0 -126
- package/dist/__tests__/plan-edit.test.js +0 -157
- package/dist/__tests__/plan-link.test.js +0 -239
- package/dist/__tests__/plan-promote.test.js +0 -181
- package/dist/__tests__/release.test.js +0 -372
- package/dist/__tests__/rotate-progress.test.js +0 -127
- package/dist/__tests__/safe-git.test.js +0 -190
- package/dist/__tests__/session-coordinator.test.js +0 -109
- package/dist/__tests__/state-bootstrap.test.js +0 -432
- package/dist/__tests__/state-doctor.test.js +0 -328
- package/dist/__tests__/sync-templates.test.js +0 -255
- package/dist/__tests__/templates-sync.test.js +0 -219
- package/dist/__tests__/trace-gen.test.js +0 -115
- package/dist/__tests__/wu-create-required-fields.test.js +0 -143
- package/dist/__tests__/wu-create-strict.test.js +0 -118
- package/dist/__tests__/wu-create.test.js +0 -121
- package/dist/__tests__/wu-done-auto-cleanup.test.js +0 -135
- package/dist/__tests__/wu-done-docs-only-policy.test.js +0 -20
- package/dist/__tests__/wu-done-staging-whitelist.test.js +0 -35
- package/dist/__tests__/wu-done.test.js +0 -36
- package/dist/__tests__/wu-edit-strict.test.js +0 -109
- package/dist/__tests__/wu-edit.test.js +0 -119
- package/dist/__tests__/wu-lifecycle-integration.test.js +0 -388
- package/dist/__tests__/wu-prep-default-exec.test.js +0 -35
- package/dist/__tests__/wu-prep.test.js +0 -140
- package/dist/__tests__/wu-proto.test.js +0 -97
- package/dist/__tests__/wu-validate-strict.test.js +0 -113
- package/dist/__tests__/wu-validate.test.js +0 -36
- package/dist/spawn-list.js +0 -143
- package/dist/spawn-list.js.map +0 -1
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { execFileSync } from 'node:child_process';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import fs from 'node:fs';
|
|
5
|
-
import os from 'node:os';
|
|
6
|
-
const CLI_SAFE_GIT_PATH = path.resolve(__dirname, '../../bin/safe-git');
|
|
7
|
-
const SCRIPTS_SAFE_GIT_PATH = path.resolve(__dirname, '../../../../../scripts/safe-git');
|
|
8
|
-
// Constants for duplicate strings
|
|
9
|
-
const SHOULD_HAVE_THROWN = 'Should have thrown an error';
|
|
10
|
-
const GIT_CMD = 'git';
|
|
11
|
-
const USER_EMAIL_CONFIG = 'user.email';
|
|
12
|
-
const USER_NAME_CONFIG = 'user.name';
|
|
13
|
-
const TEST_EMAIL = 'test@test.com';
|
|
14
|
-
const TEST_USERNAME = 'Test';
|
|
15
|
-
const FORCE_BYPASSES_LOG = 'force-bypasses.log';
|
|
16
|
-
// Create a temporary directory for testing to avoid polluting the real .lumenflow directory
|
|
17
|
-
const createTempDir = () => {
|
|
18
|
-
return fs.mkdtempSync(path.join(os.tmpdir(), 'safe-git-test-'));
|
|
19
|
-
};
|
|
20
|
-
describe('safe-git', () => {
|
|
21
|
-
// We mock child_process execution where possible, but for integration testing a script
|
|
22
|
-
// we often execute it directly. Since safe-git is a shell script, we executed it.
|
|
23
|
-
it('should fail when running "worktree remove" (CLI wrapper)', () => {
|
|
24
|
-
try {
|
|
25
|
-
execFileSync(CLI_SAFE_GIT_PATH, ['worktree', 'remove', 'some-path'], { stdio: 'pipe' });
|
|
26
|
-
expect.fail(SHOULD_HAVE_THROWN);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
const err = error;
|
|
30
|
-
expect(err.status).toBe(1);
|
|
31
|
-
expect(err.stderr.toString()).toContain("BLOCKED: Manual 'git worktree remove' is unsafe");
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
it('should fail when running "worktree remove" (scripts wrapper)', () => {
|
|
35
|
-
try {
|
|
36
|
-
execFileSync(SCRIPTS_SAFE_GIT_PATH, ['worktree', 'remove', 'some-path'], { stdio: 'pipe' });
|
|
37
|
-
expect.fail(SHOULD_HAVE_THROWN);
|
|
38
|
-
}
|
|
39
|
-
catch (error) {
|
|
40
|
-
const err = error;
|
|
41
|
-
expect(err.status).toBe(1);
|
|
42
|
-
expect(err.stderr.toString()).toContain('Manual');
|
|
43
|
-
expect(err.stderr.toString()).toContain('worktree remove');
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
it('should fail when running "reset --hard" (scripts wrapper)', () => {
|
|
47
|
-
try {
|
|
48
|
-
execFileSync(SCRIPTS_SAFE_GIT_PATH, ['reset', '--hard', 'HEAD'], { stdio: 'pipe' });
|
|
49
|
-
expect.fail(SHOULD_HAVE_THROWN);
|
|
50
|
-
}
|
|
51
|
-
catch (error) {
|
|
52
|
-
const err = error;
|
|
53
|
-
expect(err.status).toBe(1);
|
|
54
|
-
expect(err.stderr.toString()).toContain('reset --hard');
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
it('should fail when running "clean -fd" (scripts wrapper)', () => {
|
|
58
|
-
try {
|
|
59
|
-
execFileSync(SCRIPTS_SAFE_GIT_PATH, ['clean', '-fd'], { stdio: 'pipe' });
|
|
60
|
-
expect.fail(SHOULD_HAVE_THROWN);
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
const err = error;
|
|
64
|
-
expect(err.status).toBe(1);
|
|
65
|
-
expect(err.stderr.toString()).toContain('clean -fd');
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
it('should fail when running "push --force" (scripts wrapper)', () => {
|
|
69
|
-
try {
|
|
70
|
-
execFileSync(SCRIPTS_SAFE_GIT_PATH, ['push', '--force'], { stdio: 'pipe' });
|
|
71
|
-
expect.fail(SHOULD_HAVE_THROWN);
|
|
72
|
-
}
|
|
73
|
-
catch (error) {
|
|
74
|
-
const err = error;
|
|
75
|
-
expect(err.status).toBe(1);
|
|
76
|
-
expect(err.stderr.toString()).toContain('push --force');
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
it('should pass through safe commands', () => {
|
|
80
|
-
// We verify it calls git by mocking git or checking output.
|
|
81
|
-
// Since we can't easily mock the system git in a real shell script execution without PATH manip,
|
|
82
|
-
// we'll check that it runs git --version correctly.
|
|
83
|
-
const output = execFileSync(CLI_SAFE_GIT_PATH, ['--version'], { encoding: 'utf-8' });
|
|
84
|
-
expect(output).toContain('git version');
|
|
85
|
-
});
|
|
86
|
-
describe('LUMENFLOW_FORCE bypass', () => {
|
|
87
|
-
let tempDir;
|
|
88
|
-
beforeEach(() => {
|
|
89
|
-
tempDir = createTempDir();
|
|
90
|
-
});
|
|
91
|
-
afterEach(() => {
|
|
92
|
-
// Clean up temp directory
|
|
93
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
94
|
-
});
|
|
95
|
-
it('should bypass blocked commands when LUMENFLOW_FORCE=1', () => {
|
|
96
|
-
// Using git --version as a safe test with force flag
|
|
97
|
-
// The key is that the env var should be respected and not block
|
|
98
|
-
const output = execFileSync(SCRIPTS_SAFE_GIT_PATH, ['--version'], {
|
|
99
|
-
encoding: 'utf-8',
|
|
100
|
-
env: { ...process.env, LUMENFLOW_FORCE: '1' },
|
|
101
|
-
});
|
|
102
|
-
expect(output).toContain('git version');
|
|
103
|
-
});
|
|
104
|
-
it('should log bypass to force-bypasses.log when LUMENFLOW_FORCE=1', () => {
|
|
105
|
-
// We need to test that a blocked command, when forced, writes to the audit log
|
|
106
|
-
// Since reset --hard is dangerous, we use a mock approach
|
|
107
|
-
// The script should create the audit log entry before executing
|
|
108
|
-
// Create a temporary git repo for this test
|
|
109
|
-
const testRepo = path.join(tempDir, 'test-repo');
|
|
110
|
-
fs.mkdirSync(testRepo, { recursive: true });
|
|
111
|
-
execFileSync(GIT_CMD, ['init'], { cwd: testRepo, stdio: 'pipe' });
|
|
112
|
-
execFileSync(GIT_CMD, ['config', USER_EMAIL_CONFIG, TEST_EMAIL], {
|
|
113
|
-
cwd: testRepo,
|
|
114
|
-
stdio: 'pipe',
|
|
115
|
-
});
|
|
116
|
-
execFileSync(GIT_CMD, ['config', USER_NAME_CONFIG, TEST_USERNAME], {
|
|
117
|
-
cwd: testRepo,
|
|
118
|
-
stdio: 'pipe',
|
|
119
|
-
});
|
|
120
|
-
// Create a file and commit
|
|
121
|
-
fs.writeFileSync(path.join(testRepo, 'test.txt'), 'test');
|
|
122
|
-
execFileSync(GIT_CMD, ['add', '.'], { cwd: testRepo, stdio: 'pipe' });
|
|
123
|
-
execFileSync(GIT_CMD, ['commit', '-m', 'init'], { cwd: testRepo, stdio: 'pipe' });
|
|
124
|
-
// Run safe-git with force to reset --hard (should succeed with log)
|
|
125
|
-
execFileSync(SCRIPTS_SAFE_GIT_PATH, ['reset', '--hard', 'HEAD'], {
|
|
126
|
-
cwd: testRepo,
|
|
127
|
-
encoding: 'utf-8',
|
|
128
|
-
env: { ...process.env, LUMENFLOW_FORCE: '1' },
|
|
129
|
-
});
|
|
130
|
-
// Check that the force bypass log exists and contains the entry
|
|
131
|
-
const bypassLog = path.join(testRepo, '.lumenflow', FORCE_BYPASSES_LOG);
|
|
132
|
-
expect(fs.existsSync(bypassLog)).toBe(true);
|
|
133
|
-
const logContent = fs.readFileSync(bypassLog, 'utf-8');
|
|
134
|
-
expect(logContent).toContain('reset --hard');
|
|
135
|
-
expect(logContent).toContain('BYPASSED');
|
|
136
|
-
});
|
|
137
|
-
it('should include LUMENFLOW_FORCE_REASON in audit log when provided', () => {
|
|
138
|
-
const testRepo = path.join(tempDir, 'test-repo-reason');
|
|
139
|
-
fs.mkdirSync(testRepo, { recursive: true });
|
|
140
|
-
execFileSync(GIT_CMD, ['init'], { cwd: testRepo, stdio: 'pipe' });
|
|
141
|
-
execFileSync(GIT_CMD, ['config', USER_EMAIL_CONFIG, TEST_EMAIL], {
|
|
142
|
-
cwd: testRepo,
|
|
143
|
-
stdio: 'pipe',
|
|
144
|
-
});
|
|
145
|
-
execFileSync(GIT_CMD, ['config', USER_NAME_CONFIG, TEST_USERNAME], {
|
|
146
|
-
cwd: testRepo,
|
|
147
|
-
stdio: 'pipe',
|
|
148
|
-
});
|
|
149
|
-
fs.writeFileSync(path.join(testRepo, 'test.txt'), 'test');
|
|
150
|
-
execFileSync(GIT_CMD, ['add', '.'], { cwd: testRepo, stdio: 'pipe' });
|
|
151
|
-
execFileSync(GIT_CMD, ['commit', '-m', 'init'], { cwd: testRepo, stdio: 'pipe' });
|
|
152
|
-
const testReason = 'user-approved: testing bypass';
|
|
153
|
-
execFileSync(SCRIPTS_SAFE_GIT_PATH, ['reset', '--hard', 'HEAD'], {
|
|
154
|
-
cwd: testRepo,
|
|
155
|
-
encoding: 'utf-8',
|
|
156
|
-
env: { ...process.env, LUMENFLOW_FORCE: '1', LUMENFLOW_FORCE_REASON: testReason },
|
|
157
|
-
});
|
|
158
|
-
const bypassLog = path.join(testRepo, '.lumenflow', FORCE_BYPASSES_LOG);
|
|
159
|
-
const logContent = fs.readFileSync(bypassLog, 'utf-8');
|
|
160
|
-
expect(logContent).toContain(testReason);
|
|
161
|
-
});
|
|
162
|
-
it('should print warning when LUMENFLOW_FORCE used without REASON', () => {
|
|
163
|
-
const testRepo = path.join(tempDir, 'test-repo-no-reason');
|
|
164
|
-
fs.mkdirSync(testRepo, { recursive: true });
|
|
165
|
-
execFileSync(GIT_CMD, ['init'], { cwd: testRepo, stdio: 'pipe' });
|
|
166
|
-
execFileSync(GIT_CMD, ['config', USER_EMAIL_CONFIG, TEST_EMAIL], {
|
|
167
|
-
cwd: testRepo,
|
|
168
|
-
stdio: 'pipe',
|
|
169
|
-
});
|
|
170
|
-
execFileSync(GIT_CMD, ['config', USER_NAME_CONFIG, TEST_USERNAME], {
|
|
171
|
-
cwd: testRepo,
|
|
172
|
-
stdio: 'pipe',
|
|
173
|
-
});
|
|
174
|
-
fs.writeFileSync(path.join(testRepo, 'test.txt'), 'test');
|
|
175
|
-
execFileSync(GIT_CMD, ['add', '.'], { cwd: testRepo, stdio: 'pipe' });
|
|
176
|
-
execFileSync(GIT_CMD, ['commit', '-m', 'init'], { cwd: testRepo, stdio: 'pipe' });
|
|
177
|
-
// Execute with LUMENFLOW_FORCE=1 but no reason
|
|
178
|
-
execFileSync(SCRIPTS_SAFE_GIT_PATH, ['reset', '--hard', 'HEAD'], {
|
|
179
|
-
cwd: testRepo,
|
|
180
|
-
encoding: 'utf-8',
|
|
181
|
-
env: { ...process.env, LUMENFLOW_FORCE: '1' },
|
|
182
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
183
|
-
});
|
|
184
|
-
// Check the bypasslog for the NO_REASON marker
|
|
185
|
-
const bypassLog = path.join(testRepo, '.lumenflow', FORCE_BYPASSES_LOG);
|
|
186
|
-
const logContent = fs.readFileSync(bypassLog, 'utf-8');
|
|
187
|
-
expect(logContent).toContain('NO_REASON');
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
});
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Tests for session-coordinator CLI command
|
|
4
|
-
*
|
|
5
|
-
* WU-1112: INIT-003 Phase 6 - Migrate remaining Tier 1 tools
|
|
6
|
-
*
|
|
7
|
-
* Session coordinator manages agent sessions - starting, stopping,
|
|
8
|
-
* and coordinating handoffs between sessions.
|
|
9
|
-
*/
|
|
10
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
11
|
-
// Import functions under test
|
|
12
|
-
import { parseSessionArgs, SessionCommand, validateSessionCommand, } from '../session-coordinator.js';
|
|
13
|
-
describe('session-coordinator', () => {
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
vi.clearAllMocks();
|
|
16
|
-
});
|
|
17
|
-
describe('parseSessionArgs', () => {
|
|
18
|
-
it('should parse start subcommand', () => {
|
|
19
|
-
const args = parseSessionArgs(['node', 'session-coordinator.js', 'start']);
|
|
20
|
-
expect(args.command).toBe('start');
|
|
21
|
-
});
|
|
22
|
-
it('should parse stop subcommand', () => {
|
|
23
|
-
const args = parseSessionArgs(['node', 'session-coordinator.js', 'stop']);
|
|
24
|
-
expect(args.command).toBe('stop');
|
|
25
|
-
});
|
|
26
|
-
it('should parse status subcommand', () => {
|
|
27
|
-
const args = parseSessionArgs(['node', 'session-coordinator.js', 'status']);
|
|
28
|
-
expect(args.command).toBe('status');
|
|
29
|
-
});
|
|
30
|
-
it('should parse handoff subcommand', () => {
|
|
31
|
-
const args = parseSessionArgs(['node', 'session-coordinator.js', 'handoff']);
|
|
32
|
-
expect(args.command).toBe('handoff');
|
|
33
|
-
});
|
|
34
|
-
it('should parse --wu option', () => {
|
|
35
|
-
const args = parseSessionArgs(['node', 'session-coordinator.js', 'start', '--wu', 'WU-1112']);
|
|
36
|
-
expect(args.wuId).toBe('WU-1112');
|
|
37
|
-
});
|
|
38
|
-
it('should parse --agent option', () => {
|
|
39
|
-
const args = parseSessionArgs([
|
|
40
|
-
'node',
|
|
41
|
-
'session-coordinator.js',
|
|
42
|
-
'start',
|
|
43
|
-
'--agent',
|
|
44
|
-
'claude-code',
|
|
45
|
-
]);
|
|
46
|
-
expect(args.agent).toBe('claude-code');
|
|
47
|
-
});
|
|
48
|
-
it('should parse --reason option for stop', () => {
|
|
49
|
-
const args = parseSessionArgs([
|
|
50
|
-
'node',
|
|
51
|
-
'session-coordinator.js',
|
|
52
|
-
'stop',
|
|
53
|
-
'--reason',
|
|
54
|
-
'Completed work',
|
|
55
|
-
]);
|
|
56
|
-
expect(args.reason).toBe('Completed work');
|
|
57
|
-
});
|
|
58
|
-
it('should parse --help flag', () => {
|
|
59
|
-
const args = parseSessionArgs(['node', 'session-coordinator.js', '--help']);
|
|
60
|
-
expect(args.help).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
it('should default to status when no subcommand given', () => {
|
|
63
|
-
const args = parseSessionArgs(['node', 'session-coordinator.js']);
|
|
64
|
-
expect(args.command).toBe('status');
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
describe('validateSessionCommand', () => {
|
|
68
|
-
it('should accept valid start command with wu', () => {
|
|
69
|
-
const args = { command: 'start', wuId: 'WU-1112' };
|
|
70
|
-
const result = validateSessionCommand(args);
|
|
71
|
-
expect(result.valid).toBe(true);
|
|
72
|
-
});
|
|
73
|
-
it('should reject start without wu', () => {
|
|
74
|
-
const args = { command: 'start' };
|
|
75
|
-
const result = validateSessionCommand(args);
|
|
76
|
-
expect(result.valid).toBe(false);
|
|
77
|
-
expect(result.error).toContain('--wu');
|
|
78
|
-
});
|
|
79
|
-
it('should accept stop command without reason', () => {
|
|
80
|
-
const args = { command: 'stop' };
|
|
81
|
-
const result = validateSessionCommand(args);
|
|
82
|
-
expect(result.valid).toBe(true);
|
|
83
|
-
});
|
|
84
|
-
it('should accept status command', () => {
|
|
85
|
-
const args = { command: 'status' };
|
|
86
|
-
const result = validateSessionCommand(args);
|
|
87
|
-
expect(result.valid).toBe(true);
|
|
88
|
-
});
|
|
89
|
-
it('should accept handoff command with wu', () => {
|
|
90
|
-
const args = { command: 'handoff', wuId: 'WU-1112' };
|
|
91
|
-
const result = validateSessionCommand(args);
|
|
92
|
-
expect(result.valid).toBe(true);
|
|
93
|
-
});
|
|
94
|
-
it('should reject handoff without wu', () => {
|
|
95
|
-
const args = { command: 'handoff' };
|
|
96
|
-
const result = validateSessionCommand(args);
|
|
97
|
-
expect(result.valid).toBe(false);
|
|
98
|
-
expect(result.error).toContain('--wu');
|
|
99
|
-
});
|
|
100
|
-
});
|
|
101
|
-
describe('SessionCommand enum', () => {
|
|
102
|
-
it('should have all expected commands', () => {
|
|
103
|
-
expect(SessionCommand.START).toBe('start');
|
|
104
|
-
expect(SessionCommand.STOP).toBe('stop');
|
|
105
|
-
expect(SessionCommand.STATUS).toBe('status');
|
|
106
|
-
expect(SessionCommand.HANDOFF).toBe('handoff');
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
});
|