Skip to content

Commit a4038f5

Browse files
authored
new :ctx for context switching, agent files, cname (#75)
Signed-off-by: Daniel Guns <danbguns@gmail.com>
1 parent e0f26b9 commit a4038f5

9 files changed

Lines changed: 660 additions & 33 deletions

File tree

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ jobs:
7171
- name: Build Hugo site
7272
working-directory: docs
7373
run: |
74-
hugo --minify --baseURL "https://dgunzy.github.io/flux9s/"
74+
hugo --minify --baseURL "https://flux9s.ca/"
7575
7676
- name: Copy metadata.json to public
7777
working-directory: docs

AGENTS.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# flux9s Development Instructions
2+
3+
## Core Philosophy
4+
5+
- **Zero-maintenance model updates**: Use code generation over manual types
6+
- **Non-blocking operations**: Keep UI responsive with async task spawning
7+
- **Graceful degradation**: Log errors, don't crash (only panic for truly unrecoverable errors)
8+
- **K9s alignment**: Follow K9s conventions for keybindings and UX
9+
10+
## Before You Start
11+
12+
1. Run `make ci` after all changes (formats, lints, tests)
13+
2. Large changes require accompanying tests
14+
3. Command/keybinding changes must update help text (`src/tui/views/help.rs` and footer)
15+
16+
## Code Standards
17+
18+
### Error Handling
19+
20+
```rust
21+
// ✅ Good - Add context to errors
22+
api.patch(name, &params, &patch)
23+
.await
24+
.context(format!("Failed to suspend {}/{}", resource_type, name))?;
25+
26+
// ✅ Good - Log errors, return Result
27+
if let Err(e) = operation() {
28+
tracing::warn!("Operation failed: {}", e);
29+
return Ok(()); // Continue execution
30+
}
31+
32+
// ❌ Bad - Missing context
33+
api.patch(name, &params, &patch).await?;
34+
35+
// ❌ Bad - Unwrap (use only in tests)
36+
let value = result.unwrap();
37+
```
38+
39+
### State Management
40+
41+
- Use `Arc<RwLock<>>` only when truly shared across threads
42+
- Prefer simple `HashMap`/`Vec` for single-threaded state
43+
- Keep `App` struct focused - extract complex state into sub-structs
44+
45+
### Async Operations
46+
47+
```rust
48+
// ✅ Good - Spawn tasks, use channels for results
49+
let (tx, rx) = tokio::sync::oneshot::channel();
50+
self.pending_rx = Some(rx);
51+
tokio::spawn(async move {
52+
let result = operation().await;
53+
let _ = tx.send(result);
54+
});
55+
56+
// Later, poll for results
57+
if let Some(result) = app.try_get_result() {
58+
app.handle_result(result);
59+
}
60+
```
61+
62+
### Type Safety
63+
64+
```rust
65+
// ✅ Good - Use proper types
66+
struct ResourceKey {
67+
resource_type: String,
68+
namespace: String,
69+
name: String,
70+
}
71+
72+
// ❌ Bad - Tuple types or string parsing
73+
type Request = (String, String, String); // What do these mean?
74+
let parts: Vec<&str> = key.split(':').collect(); // Fragile
75+
```
76+
77+
### Adding New Resource Types
78+
79+
1. Ensure CRD is in `crds/` directory
80+
2. Run `./scripts/update-flux.sh` to regenerate models
81+
3. Add to `FluxResourceKind` enum
82+
4. Add `impl_watchable!` macro usage
83+
5. Register in `ResourceRegistry`
84+
6. Add to `fetch_resource!` match in `src/tui/mod.rs`
85+
7. Update tests in `tests/resource_registry.rs`
86+
87+
**Important**: Always use `FluxResourceKind` enum and `get_gvk_for_resource_type()` helper function
88+
instead of hardcoding resource types, API groups, versions, or plural names. This ensures a single
89+
source of truth and prevents inconsistencies when Flux versions change.
90+
91+
### Adding New Operations
92+
93+
1. Implement `FluxOperation` trait
94+
2. Register in `OperationRegistry::new()`
95+
3. Add keybinding to footer (`src/tui/views/footer.rs`)
96+
4. Add to help text (`src/tui/views/help.rs`)
97+
5. Write operation tests
98+
99+
### View Components
100+
101+
- Keep views stateless - they receive all needed data as parameters
102+
- Extract complex rendering logic into helper functions
103+
- Use theme colors consistently (never hardcode colors)
104+
- Handle small terminal sizes gracefully
105+
106+
## Testing Requirements
107+
108+
### What to Test
109+
110+
- ✅ CRD compatibility (status field extraction)
111+
- ✅ Resource registry completeness
112+
- ✅ Field extraction from resources
113+
- ✅ Operation validity for resource types
114+
- ❌ Don't over-test generated code (trust kopium)
115+
116+
### Test Organization
117+
118+
```rust
119+
// Unit tests in module
120+
#[cfg(test)]
121+
mod tests {
122+
use super::*;
123+
124+
#[test]
125+
fn test_behavior() {
126+
// Test logic
127+
}
128+
}
129+
130+
// Integration tests in tests/ directory
131+
// tests/crd_compatibility.rs
132+
// tests/resource_registry.rs
133+
```
134+
135+
## Common Patterns
136+
137+
### Resource Key Format
138+
139+
- Always use `resource_type:namespace:name` format
140+
- Consider creating `ResourceKey` type for type safety
141+
142+
### Channel Management
143+
144+
- Use `oneshot::channel()` for single-response operations
145+
- Store `Receiver` in `App`, spawn task with `Sender`
146+
- Poll with `try_recv()` in main loop (non-blocking)
147+
148+
### Theme Usage
149+
150+
```rust
151+
// ✅ Good - Use theme methods
152+
let style = self.theme.status_ready_style();
153+
let text = Span::styled("Ready", style);
154+
155+
// ❌ Bad - Hardcode colors
156+
let text = Span::styled("Ready", Style::default().fg(Color::Green));
157+
```
158+
159+
## CI/CD
160+
161+
- `make ci` runs: `cargo fmt`, `cargo clippy`, `cargo test`
162+
- All CI checks must pass before merge
163+
- Clippy warnings are treated as errors
164+
- Generated code in `src/models/_generated/` has clippy suppressed
165+
166+
## Documentation
167+
168+
- Public API should have doc comments
169+
- Complex logic deserves inline comments
170+
- Update DEVELOPER_GUIDE.md for architectural changes
171+
- Update README.md for user-facing changes
172+
- **Update docs site**: When making user-facing changes (features, commands, operations, configuration), update the documentation site in `docs/` as part of the same work
173+
174+
## Performance
175+
176+
- Profile before optimizing
177+
- Watch API efficiency is critical - use namespaced APIs when possible
178+
- Defer expensive operations (don't block UI)
179+
- Cache layout dimensions to prevent flicker (see `cached_header_height`)
180+
181+
## Common Gotchas
182+
183+
- Don't forget to invalidate layout cache when state affecting layout changes
184+
- Always check `config.read_only` before write operations
185+
- Update both `NO_PROXY` and `no_proxy` for environment compatibility
186+
- Generated models are version-controlled for reproducible builds
187+
- **Never hardcode Flux resource types, API groups, versions, or plural names** - always use `FluxResourceKind` enum and `get_gvk_for_resource_type()` helper function to ensure single source of truth

CLAUDE.md

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
# flux9s Development Instructions
2+
3+
## Core Philosophy
4+
5+
- **Zero-maintenance model updates**: Use code generation over manual types
6+
- **Non-blocking operations**: Keep UI responsive with async task spawning
7+
- **Graceful degradation**: Log errors, don't crash (only panic for truly unrecoverable errors)
8+
- **K9s alignment**: Follow K9s conventions for keybindings and UX
9+
10+
## Before You Start
11+
12+
1. Run `make ci` after all changes (formats, lints, tests)
13+
2. Large changes require accompanying tests
14+
3. Command/keybinding changes must update help text (`src/tui/views/help.rs` and footer)
15+
16+
## Code Standards
17+
18+
### Error Handling
19+
20+
```rust
21+
// ✅ Good - Add context to errors
22+
api.patch(name, &params, &patch)
23+
.await
24+
.context(format!("Failed to suspend {}/{}", resource_type, name))?;
25+
26+
// ✅ Good - Log errors, return Result
27+
if let Err(e) = operation() {
28+
tracing::warn!("Operation failed: {}", e);
29+
return Ok(()); // Continue execution
30+
}
31+
32+
// ❌ Bad - Missing context
33+
api.patch(name, &params, &patch).await?;
34+
35+
// ❌ Bad - Unwrap (use only in tests)
36+
let value = result.unwrap();
37+
```
38+
39+
### State Management
40+
41+
- Use `Arc<RwLock<>>` only when truly shared across threads
42+
- Prefer simple `HashMap`/`Vec` for single-threaded state
43+
- Keep `App` struct focused - extract complex state into sub-structs
44+
45+
### Async Operations
46+
47+
```rust
48+
// ✅ Good - Spawn tasks, use channels for results
49+
let (tx, rx) = tokio::sync::oneshot::channel();
50+
self.pending_rx = Some(rx);
51+
tokio::spawn(async move {
52+
let result = operation().await;
53+
let _ = tx.send(result);
54+
});
55+
56+
// Later, poll for results
57+
if let Some(result) = app.try_get_result() {
58+
app.handle_result(result);
59+
}
60+
```
61+
62+
### Type Safety
63+
64+
```rust
65+
// ✅ Good - Use proper types
66+
struct ResourceKey {
67+
resource_type: String,
68+
namespace: String,
69+
name: String,
70+
}
71+
72+
// ❌ Bad - Tuple types or string parsing
73+
type Request = (String, String, String); // What do these mean?
74+
let parts: Vec<&str> = key.split(':').collect(); // Fragile
75+
```
76+
77+
### Adding New Resource Types
78+
79+
1. Ensure CRD is in `crds/` directory
80+
2. Run `./scripts/update-flux.sh` to regenerate models
81+
3. Add to `FluxResourceKind` enum
82+
4. Add `impl_watchable!` macro usage
83+
5. Register in `ResourceRegistry`
84+
6. Add to `fetch_resource!` match in `src/tui/mod.rs`
85+
7. Update tests in `tests/resource_registry.rs`
86+
87+
**Important**: Always use `FluxResourceKind` enum and `get_gvk_for_resource_type()` helper function
88+
instead of hardcoding resource types, API groups, versions, or plural names. This ensures a single
89+
source of truth and prevents inconsistencies when Flux versions change.
90+
91+
### Adding New Operations
92+
93+
1. Implement `FluxOperation` trait
94+
2. Register in `OperationRegistry::new()`
95+
3. Add keybinding to footer (`src/tui/views/footer.rs`)
96+
4. Add to help text (`src/tui/views/help.rs`)
97+
5. Write operation tests
98+
99+
### View Components
100+
101+
- Keep views stateless - they receive all needed data as parameters
102+
- Extract complex rendering logic into helper functions
103+
- Use theme colors consistently (never hardcode colors)
104+
- Handle small terminal sizes gracefully
105+
106+
## Testing Requirements
107+
108+
### What to Test
109+
110+
- ✅ CRD compatibility (status field extraction)
111+
- ✅ Resource registry completeness
112+
- ✅ Field extraction from resources
113+
- ✅ Operation validity for resource types
114+
- ❌ Don't over-test generated code (trust kopium)
115+
116+
### Test Organization
117+
118+
```rust
119+
// Unit tests in module
120+
#[cfg(test)]
121+
mod tests {
122+
use super::*;
123+
124+
#[test]
125+
fn test_behavior() {
126+
// Test logic
127+
}
128+
}
129+
130+
// Integration tests in tests/ directory
131+
// tests/crd_compatibility.rs
132+
// tests/resource_registry.rs
133+
```
134+
135+
## Common Patterns
136+
137+
### Resource Key Format
138+
139+
- Always use `resource_type:namespace:name` format
140+
- Consider creating `ResourceKey` type for type safety
141+
142+
### Channel Management
143+
144+
- Use `oneshot::channel()` for single-response operations
145+
- Store `Receiver` in `App`, spawn task with `Sender`
146+
- Poll with `try_recv()` in main loop (non-blocking)
147+
148+
### Theme Usage
149+
150+
```rust
151+
// ✅ Good - Use theme methods
152+
let style = self.theme.status_ready_style();
153+
let text = Span::styled("Ready", style);
154+
155+
// ❌ Bad - Hardcode colors
156+
let text = Span::styled("Ready", Style::default().fg(Color::Green));
157+
```
158+
159+
## CI/CD
160+
161+
- `make ci` runs: `cargo fmt`, `cargo clippy`, `cargo test`
162+
- All CI checks must pass before merge
163+
- Clippy warnings are treated as errors
164+
- Generated code in `src/models/_generated/` has clippy suppressed
165+
166+
## Documentation
167+
168+
- Public API should have doc comments
169+
- Complex logic deserves inline comments
170+
- Update DEVELOPER_GUIDE.md for architectural changes
171+
- Update README.md for user-facing changes
172+
- **Update docs site**: When making user-facing changes (features, commands, operations, configuration), update the documentation site in `docs/` as part of the same work
173+
174+
## Performance
175+
176+
- Profile before optimizing
177+
- Watch API efficiency is critical - use namespaced APIs when possible
178+
- Defer expensive operations (don't block UI)
179+
- Cache layout dimensions to prevent flicker (see `cached_header_height`)
180+
181+
## Common Gotchas
182+
183+
- Don't forget to invalidate layout cache when state affecting layout changes
184+
- Always check `config.read_only` before write operations
185+
- Update both `NO_PROXY` and `no_proxy` for environment compatibility
186+
- Generated models are version-controlled for reproducible builds
187+
- **Never hardcode Flux resource types, API groups, versions, or plural names** - always use `FluxResourceKind` enum and `get_gvk_for_resource_type()` helper function to ensure single source of truth

docs/config.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
baseURL = 'https://dgunzy.github.io/flux9s/'
1+
baseURL = 'https://flux9s.ca/'
22
title = 'flux9s Documentation'
33
description = 'A K9s-inspired terminal UI for monitoring Flux GitOps resources in real-time'
44

@@ -88,7 +88,7 @@ buildFuture = false
8888
desc = "View on crates.io"
8989
[[params.links.user]]
9090
name = "Homebrew"
91-
url = "https://formulae.brew.sh/formula/flux9s"
91+
url = "https://github.com/dgunzy/homebrew-tap"
9292
icon = "fas fa-beer"
9393
desc = "Install via Homebrew"
9494

0 commit comments

Comments
 (0)