Skip to content

Commit 0beae7d

Browse files
committed
cli: Fix test hygiene and remove unused imports
1 parent 51edaf1 commit 0beae7d

7 files changed

Lines changed: 570 additions & 7 deletions

File tree

cli/README.md

Lines changed: 374 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,374 @@
1+
# sce - Shared Context Engineering CLI
2+
3+
A Rust CLI for Shared Context Engineering workflows, including WorkOS SSO authentication and local Agent Trace attribution.
4+
5+
## Overview
6+
7+
The `sce` CLI provides:
8+
- **Authentication**: WorkOS SSO/OIDC via OAuth 2.0 Device Authorization Flow
9+
- **Setup**: Install OpenCode and Claude configuration files and git hooks
10+
- **Doctor**: Validate local git-hook installation readiness
11+
- **Agent Trace**: Git hooks for local attribution tracking
12+
- **Config**: Inspect and validate runtime configuration
13+
14+
Some commands remain in placeholder state (`mcp`, `sync`) and are under active development.
15+
16+
## Installation
17+
18+
### Local Cargo Install
19+
20+
```bash
21+
cargo install --path cli --locked
22+
```
23+
24+
### Nix Flake
25+
26+
Build the release package:
27+
```bash
28+
nix build ./cli#default
29+
```
30+
31+
Run directly:
32+
```bash
33+
nix run ./cli#sce -- --help
34+
```
35+
36+
## Quick Start
37+
38+
```bash
39+
# View available commands
40+
sce --help
41+
42+
# Configure WorkOS (required for auth commands)
43+
export WORKOS_CLIENT_ID="client_your_client_id"
44+
45+
# Authenticate with WorkOS
46+
sce login
47+
48+
# Check authentication status
49+
sce auth status
50+
51+
# Set up local repository
52+
sce setup
53+
54+
# Validate hook installation
55+
sce doctor
56+
57+
# Log out when done
58+
sce logout
59+
```
60+
61+
## Authentication
62+
63+
The CLI uses WorkOS SSO/OIDC authentication via the OAuth 2.0 Device Authorization Flow (RFC 8628). Authentication is required for the `sync` command.
64+
65+
### Configuration
66+
67+
Set your WorkOS client ID via environment variable or config file:
68+
69+
**Environment Variable (recommended):**
70+
```bash
71+
export WORKOS_CLIENT_ID="client_your_client_id"
72+
```
73+
74+
**Config File:**
75+
76+
Create `.sce/config.json` in your repository or `${XDG_STATE_HOME:-~/.local/state}/sce/config.json` for global config:
77+
78+
```json
79+
{
80+
"workos_client_id": "client_your_client_id"
81+
}
82+
```
83+
84+
### Login
85+
86+
Start the device authorization flow:
87+
88+
```bash
89+
sce login
90+
```
91+
92+
The CLI will:
93+
1. Request a device code from WorkOS
94+
2. Display a verification URL and user code
95+
3. Poll WorkOS until you complete authentication in your browser
96+
4. Store the access token and refresh token locally
97+
98+
Example output:
99+
```
100+
WorkOS login required
101+
Open this URL: https://workos.com/device?user_code=ABCD-EFGH
102+
User code: ABCD-EFGH
103+
Waiting for authorization... (polling every 5s)
104+
Authentication successful. Stored WorkOS credentials at '/home/user/.local/state/sce/auth/tokens.json' and issued access token lifetime is 3600s.
105+
```
106+
107+
### Check Authentication Status
108+
109+
```bash
110+
# Text output (default)
111+
sce auth status
112+
113+
# JSON output
114+
sce auth status --format json
115+
```
116+
117+
Example output:
118+
```
119+
Authenticated. Token expires in 1 hours.
120+
```
121+
122+
JSON output includes:
123+
```json
124+
{
125+
"status": "ok",
126+
"command": "auth status",
127+
"authenticated": true,
128+
"token_status": "valid",
129+
"expires_at": "2024-01-15T12:00:00+00:00",
130+
"expires_in_seconds": 3600
131+
}
132+
```
133+
134+
### Logout
135+
136+
Remove stored credentials:
137+
138+
```bash
139+
sce logout
140+
```
141+
142+
Example output:
143+
```
144+
Logged out successfully. Removed stored WorkOS credentials at '/home/user/.local/state/sce/auth/tokens.json'.
145+
```
146+
147+
### Token Storage
148+
149+
Tokens are stored locally with restricted file permissions:
150+
151+
| Platform | Path | Permissions |
152+
|----------|------|-------------|
153+
| Linux | `${XDG_STATE_HOME:-~/.local/state}/sce/auth/tokens.json` | 0600 (owner read/write) |
154+
| macOS | `~/Library/Application Support/sce/auth/tokens.json` | User-only |
155+
| Windows | `%APPDATA%\sce\auth\tokens.json` | User-only ACL |
156+
157+
**Security Notes:**
158+
- Tokens are stored unencrypted (filesystem permissions provide protection)
159+
- For production use, consider OS keychain integration (future enhancement)
160+
- Access tokens typically expire after 1 hour
161+
- Refresh tokens are used to automatically obtain new access tokens
162+
- If both tokens expire, re-authentication is required
163+
164+
### Token Refresh
165+
166+
The CLI automatically refreshes expired access tokens using the refresh token when:
167+
- Running `sce sync` (authentication is checked before execution)
168+
- The access token has expired but the refresh token is still valid
169+
170+
If the refresh token expires, you'll need to run `sce login` again.
171+
172+
## Command Reference
173+
174+
### Implemented Commands
175+
176+
| Command | Description |
177+
|---------|-------------|
178+
| `sce --help` | Show available commands |
179+
| `sce login` | Authenticate with WorkOS via device flow |
180+
| `sce logout` | Clear stored WorkOS credentials |
181+
| `sce auth status` | Show authentication state |
182+
| `sce config show` | Display resolved configuration |
183+
| `sce config validate` | Validate configuration settings |
184+
| `sce setup` | Install config files and git hooks |
185+
| `sce doctor` | Validate git-hook installation |
186+
| `sce hooks <subcommand>` | Run git-hook entrypoints |
187+
| `sce version` | Print version information |
188+
| `sce completion --shell <bash\|zsh\|fish>` | Generate shell completion |
189+
190+
### Placeholder Commands
191+
192+
| Command | Description |
193+
|---------|-------------|
194+
| `sce mcp` | MCP file-cache tooling (planned) |
195+
| `sce sync` | Cloud sync workflows (requires auth) |
196+
197+
## Setup Command
198+
199+
Install OpenCode/Claude configuration and required git hooks:
200+
201+
```bash
202+
# Interactive setup (default)
203+
sce setup
204+
205+
# Non-interactive with target selection
206+
sce setup --opencode --non-interactive
207+
sce setup --claude --non-interactive
208+
sce setup --both --non-interactive
209+
210+
# Install hooks only
211+
sce setup --hooks
212+
213+
# Install hooks for a specific repository
214+
sce setup --hooks --repo /path/to/repo
215+
216+
# Combined: config + hooks
217+
sce setup --opencode --hooks
218+
```
219+
220+
## Configuration
221+
222+
### Configuration Precedence
223+
224+
Values are resolved in this order (later overrides earlier):
225+
1. Defaults
226+
2. Config file (global then local)
227+
3. Environment variables
228+
4. Command-line flags
229+
230+
### Environment Variables
231+
232+
| Variable | Description |
233+
|----------|-------------|
234+
| `WORKOS_CLIENT_ID` | WorkOS client ID for authentication |
235+
| `SCE_CONFIG_FILE` | Path to config file |
236+
| `SCE_LOG_LEVEL` | Log threshold: `error`, `warn`, `info`, `debug` |
237+
| `SCE_LOG_FORMAT` | Log format: `text`, `json` |
238+
| `SCE_LOG_FILE` | Optional log file path |
239+
| `SCE_LOG_FILE_MODE` | File mode: `truncate` (default), `append` |
240+
| `SCE_OTEL_ENABLED` | Enable OpenTelemetry: `true`, `false` |
241+
242+
### Config File Schema
243+
244+
```json
245+
{
246+
"log_level": "info",
247+
"timeout_ms": 30000,
248+
"workos_client_id": "client_your_client_id"
249+
}
250+
```
251+
252+
## Troubleshooting
253+
254+
### "WorkOS client ID is not configured"
255+
256+
**Cause**: `WORKOS_CLIENT_ID` environment variable is not set and no config file contains `workos_client_id`.
257+
258+
**Solution**:
259+
```bash
260+
export WORKOS_CLIENT_ID="client_your_client_id"
261+
sce login
262+
```
263+
264+
### "Not authenticated. Run 'sce login' to authenticate."
265+
266+
**Cause**: No stored tokens found.
267+
268+
**Solution**:
269+
```bash
270+
sce login
271+
```
272+
273+
### "Token has expired. Run 'sce login' to re-authenticate."
274+
275+
**Cause**: Both access token and refresh token have expired.
276+
277+
**Solution**:
278+
```bash
279+
sce login
280+
```
281+
282+
### "Stored authentication tokens are invalid"
283+
284+
**Cause**: Token file is corrupted or malformed.
285+
286+
**Solution**:
287+
```bash
288+
sce logout
289+
sce login
290+
```
291+
292+
### "Failed to resolve token storage path"
293+
294+
**Cause**: Home directory or state directory cannot be resolved.
295+
296+
**Solution**:
297+
- Ensure `HOME` environment variable is set (Linux/macOS)
298+
- Ensure `USERPROFILE` environment variable is set (Windows)
299+
- On Linux, ensure XDG directories are accessible
300+
301+
### Device Authorization Timeout
302+
303+
**Cause**: Device code expired before authentication was completed (typically 10-30 minutes).
304+
305+
**Solution**:
306+
```bash
307+
sce login
308+
# Complete authentication in browser within the time limit
309+
```
310+
311+
### Permission Denied on Token File
312+
313+
**Cause**: Token file permissions are incorrect or directory is not writable.
314+
315+
**Solution**:
316+
```bash
317+
# Check permissions
318+
ls -la ~/.local/state/sce/auth/
319+
320+
# Remove and re-authenticate
321+
sce logout
322+
sce login
323+
```
324+
325+
### "Run 'sce login' first" when running sync
326+
327+
**Cause**: The `sync` command requires valid authentication.
328+
329+
**Solution**:
330+
```bash
331+
# Check current auth status
332+
sce auth status
333+
334+
# If not authenticated, log in
335+
sce login
336+
337+
# Then run sync
338+
sce sync
339+
```
340+
341+
## Exit Codes
342+
343+
| Code | Class | Description |
344+
|------|-------|-------------|
345+
| 0 | Success | Command completed successfully |
346+
| 2 | Parse | Invalid command syntax or unknown options |
347+
| 3 | Validation | Invalid arguments or configuration |
348+
| 4 | Runtime | Command execution failed |
349+
| 5 | Dependency | Required runtime dependencies unavailable |
350+
351+
## Development
352+
353+
### Build
354+
355+
```bash
356+
cargo build --manifest-path cli/Cargo.toml
357+
```
358+
359+
### Test
360+
361+
```bash
362+
cargo test --manifest-path cli/Cargo.toml
363+
```
364+
365+
### Run Checks
366+
367+
```bash
368+
cargo fmt --check --manifest-path cli/Cargo.toml
369+
cargo clippy --manifest-path cli/Cargo.toml
370+
```
371+
372+
## License
373+
374+
See repository root for license information.

cli/src/services/setup/tests.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,9 +526,15 @@ fn required_hook_install_updates_noncanonical_hook_in_custom_hooks_path() -> Res
526526
let temp = TestTempDir::new("sce-setup-hook-install-tests")?;
527527
init_git_repo(temp.path())?;
528528

529-
run_git_in_repo(temp.path(), &["config", "core.hooksPath", ".githooks"])?;
530-
531529
let custom_hooks_directory = temp.path().join(".githooks");
530+
run_git_in_repo(
531+
temp.path(),
532+
&[
533+
"config",
534+
"core.hooksPath",
535+
custom_hooks_directory.to_str().unwrap(),
536+
],
537+
)?;
532538
fs::create_dir_all(&custom_hooks_directory)?;
533539
let commit_msg_path = custom_hooks_directory.join("commit-msg");
534540
fs::write(&commit_msg_path, b"#!/bin/sh\necho legacy\n")?;

0 commit comments

Comments
 (0)