|
| 1 | +# PR Summary: Modular Command Output Architecture |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This PR introduces a **3-layer modular architecture** for CLI command formatting, extracting the excellent design work from `forest edges propose` into reusable components. |
| 6 | + |
| 7 | +**Status**: Phase 1 Complete - Color utilities ready to use |
| 8 | +**Impact**: Foundation for consistent, maintainable command output across all Forest CLI commands |
| 9 | + |
| 10 | +## Problem Statement |
| 11 | + |
| 12 | +Currently, the beautiful color gradients and formatting logic in `forest edges propose` (146 lines) are trapped in a single function and cannot be reused by other commands. Each command that wants colorful output would need to reinvent this logic. |
| 13 | + |
| 14 | +## Solution |
| 15 | + |
| 16 | +Extract formatting into a **3-layer architecture**: |
| 17 | + |
| 18 | +``` |
| 19 | +Command Layer (orchestration) → Core Layer (data) → Formatter Layer (presentation) |
| 20 | +``` |
| 21 | + |
| 22 | +### What's Included |
| 23 | + |
| 24 | +#### 1. New Formatter Module (`src/cli/formatters/`) |
| 25 | + |
| 26 | +**Color Utilities** (`colors.ts`): |
| 27 | +- `colorize.*` - Preset color functions for common use cases |
| 28 | +- `hslToRgb()` - HSL to RGB conversion for gradient heat maps |
| 29 | +- `colorizeScore()` - Gradient coloring based on value (0.0-1.0) |
| 30 | +- `colorNodeId()` - Subtle per-character hue variation for IDs |
| 31 | +- `FOREST_THEMES` - Central color palette (amber, forest green, moss, etc.) |
| 32 | + |
| 33 | +**Edge Formatters** (`edges.ts`): |
| 34 | +- `formatEdgeSuggestionsTable()` - Beautiful table with colored scores |
| 35 | +- `formatEdgeSuggestionsJSON()` - JSON output |
| 36 | +- `formatAcceptedEdgesTable()` - Accepted edges list |
| 37 | +- `formatEdgeExplanation()` - Score breakdown |
| 38 | + |
| 39 | +**Public API** (`index.ts`): |
| 40 | +- Clean import point for all formatters |
| 41 | +- `import { colorize, formatEdgeSuggestionsTable } from '../formatters'` |
| 42 | + |
| 43 | +#### 2. Documentation |
| 44 | + |
| 45 | +- **`MODULAR_COMMANDS_GUIDE.md`** - Quick start and phased migration plan |
| 46 | +- **`FORMATTING_ARCHITECTURE.md`** - Full architectural specification |
| 47 | +- **`src/cli/formatters/README.md`** - Formatter module documentation |
| 48 | +- **`src/cli/formatters/MIGRATION_EXAMPLE.md`** - Before/after examples |
| 49 | + |
| 50 | +#### 3. Dependencies |
| 51 | + |
| 52 | +Added to `package.json`: |
| 53 | +- `chalk@^4.1.2` - Terminal color support (already used in `edges.ts`) |
| 54 | +- `@clack/prompts@^0.7.0` - Interactive prompts (already used in `config.ts`) |
| 55 | + |
| 56 | +## Benefits |
| 57 | + |
| 58 | +### 1. Reusability |
| 59 | +```typescript |
| 60 | +// ANY command can now use Forest colors! |
| 61 | +import { colorize } from '../formatters'; |
| 62 | + |
| 63 | +console.log(colorize.embeddingScore(0.85)); // Green gradient |
| 64 | +console.log(colorize.nodeId("7fa7acb2")); // Subtle grey |
| 65 | +``` |
| 66 | + |
| 67 | +### 2. Consistency |
| 68 | +All commands use the same color palette (FOREST_THEMES) for cohesive UX. |
| 69 | + |
| 70 | +### 3. Maintainability |
| 71 | +Change color scheme in one place (`colors.ts`), all commands update automatically. |
| 72 | + |
| 73 | +### 4. Testability |
| 74 | +Pure functions are easy to test - input data → formatted string. |
| 75 | + |
| 76 | +### 5. Discoverability |
| 77 | +Clear directory structure: `src/cli/formatters/` - obvious location for presentation logic. |
| 78 | + |
| 79 | +## Non-Breaking Changes |
| 80 | + |
| 81 | +✅ **Zero breaking changes** - This PR only adds new utilities |
| 82 | +✅ Existing commands continue to work unchanged |
| 83 | +✅ No behavior modifications |
| 84 | +✅ Pure additive changes |
| 85 | + |
| 86 | +## Usage Examples |
| 87 | + |
| 88 | +### Example 1: Add Color to Stats |
| 89 | + |
| 90 | +```typescript |
| 91 | +// src/cli/commands/stats.ts |
| 92 | +import { colorize } from '../formatters'; |
| 93 | + |
| 94 | +console.log('High-degree nodes:'); |
| 95 | +for (const entry of stats.highDegree) { |
| 96 | + console.log( |
| 97 | + ` ${colorize.nodeId(formatId(entry.id))} ${entry.title} ` + |
| 98 | + `(degree ${colorize.embeddingScore(entry.degree / maxDegree)})` |
| 99 | + ); |
| 100 | +} |
| 101 | +``` |
| 102 | + |
| 103 | +### Example 2: Add Color to Search |
| 104 | + |
| 105 | +```typescript |
| 106 | +// src/cli/commands/search.ts |
| 107 | +import { colorize } from '../formatters'; |
| 108 | + |
| 109 | +for (const item of result.nodes) { |
| 110 | + const score = colorize.embeddingScore(item.similarity); |
| 111 | + const id = colorize.nodeId(formatNodeId(item.node.id)); |
| 112 | + console.log(`${score} ${id} ${item.node.title}`); |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +### Example 3: Refactor Edge Commands (Future) |
| 117 | + |
| 118 | +```typescript |
| 119 | +// Instead of 146 lines of inline formatting: |
| 120 | +const suggestions = await getTopSuggestionsCore(limit); |
| 121 | +console.log(formatEdgeSuggestionsTable(suggestions, { |
| 122 | + longIds: flags.longIds, |
| 123 | + showHeader: true, |
| 124 | +})); |
| 125 | +``` |
| 126 | + |
| 127 | +## File Structure |
| 128 | + |
| 129 | +``` |
| 130 | +src/cli/formatters/ |
| 131 | +├── colors.ts # Color utilities (198 lines) |
| 132 | +├── edges.ts # Edge formatters (234 lines) |
| 133 | +├── index.ts # Public API (42 lines) |
| 134 | +├── README.md # Module documentation |
| 135 | +└── MIGRATION_EXAMPLE.md # Refactoring examples |
| 136 | +
|
| 137 | +Root documentation/ |
| 138 | +├── MODULAR_COMMANDS_GUIDE.md # Implementation guide |
| 139 | +└── FORMATTING_ARCHITECTURE.md # Architecture spec |
| 140 | +``` |
| 141 | + |
| 142 | +## Next Steps (Future PRs) |
| 143 | + |
| 144 | +This PR establishes the foundation. Recommended phased migration: |
| 145 | + |
| 146 | +1. **Phase 2**: Create core functions (`src/core/edges.ts`) |
| 147 | + - Extract business logic from commands |
| 148 | + - `getTopSuggestionsCore()`, `getAcceptedEdgesCore()`, etc. |
| 149 | + |
| 150 | +2. **Phase 3**: Migrate edge commands to use formatters |
| 151 | + - Refactor `runEdgesPropose()`, `runEdgesExplain()`, etc. |
| 152 | + - Verify output unchanged (visual regression) |
| 153 | + |
| 154 | +3. **Phase 4**: Apply pattern to other commands |
| 155 | + - `stats`, `search`, `explore` |
| 156 | + - Create `stats.ts`, `search.ts`, `nodes.ts` formatters |
| 157 | + |
| 158 | +4. **Phase 5**: Generic table utilities (optional) |
| 159 | + - Reusable table building blocks |
| 160 | + - Column definitions, alignment, etc. |
| 161 | + |
| 162 | +## Testing Strategy |
| 163 | + |
| 164 | +**Current PR** (Phase 1): |
| 165 | +- No behavior changes, no tests needed yet |
| 166 | +- TypeScript compilation validates types |
| 167 | + |
| 168 | +**Future PRs**: |
| 169 | +- Unit tests for formatters (pure functions) |
| 170 | +- Visual regression tests for command output |
| 171 | +- Integration tests for core functions |
| 172 | + |
| 173 | +## Dependencies |
| 174 | + |
| 175 | +```json |
| 176 | +{ |
| 177 | + "dependencies": { |
| 178 | + "chalk": "^4.1.2", // Terminal colors (NEW) |
| 179 | + "@clack/prompts": "^0.7.0" // Interactive prompts (NEW) |
| 180 | + } |
| 181 | +} |
| 182 | +``` |
| 183 | + |
| 184 | +⚠️ **Note**: These dependencies are already imported in existing code but were missing from `package.json`. This PR adds them explicitly. |
| 185 | + |
| 186 | +## Documentation Highlights |
| 187 | + |
| 188 | +### For Developers |
| 189 | +- **`MODULAR_COMMANDS_GUIDE.md`** - Start here! Quick start and phased approach |
| 190 | +- **`FORMATTING_ARCHITECTURE.md`** - Deep dive into architecture decisions |
| 191 | + |
| 192 | +### For Command Authors |
| 193 | +- **`src/cli/formatters/README.md`** - How to use the formatters |
| 194 | +- **`MIGRATION_EXAMPLE.md`** - Concrete before/after refactoring |
| 195 | + |
| 196 | +## Color Palette (FOREST_THEMES) |
| 197 | + |
| 198 | +The formatter uses a natural forest-inspired palette: |
| 199 | + |
| 200 | +- **Aggregate**: Amber/bark brown (hue 35) |
| 201 | +- **Embedding**: Forest green (hue 120) |
| 202 | +- **Token**: Moss/lime green (hue 100) |
| 203 | +- **Title**: Autumn gold (hue 45) |
| 204 | +- **Tag**: Clay/rust red (hue 10) |
| 205 | +- **Node A**: Sky blue (#A8C5DD) |
| 206 | +- **Node B**: Sage green (#A8DDB5) |
| 207 | +- **Edge Code**: Dark orange (#FF8C00) |
| 208 | + |
| 209 | +All score colors use gradient heat maps: darker = lower, brighter = higher. |
| 210 | + |
| 211 | +## Review Checklist |
| 212 | + |
| 213 | +- [x] TypeScript types defined for all public APIs |
| 214 | +- [x] Functions documented with JSDoc |
| 215 | +- [x] README created for formatter module |
| 216 | +- [x] Architecture documentation written |
| 217 | +- [x] Migration examples provided |
| 218 | +- [x] Dependencies added to package.json |
| 219 | +- [x] Non-breaking changes only |
| 220 | +- [x] Phased rollout plan documented |
| 221 | + |
| 222 | +## Questions for Reviewers |
| 223 | + |
| 224 | +1. **API preferences**: Functions vs classes for formatters? |
| 225 | +2. **JSON standardization**: Should we define schemas in `src/types/output.ts`? |
| 226 | +3. **Color themes**: Should themes be configurable or hardcoded? |
| 227 | +4. **Testing strategy**: Snapshot tests? Visual regression? |
| 228 | + |
| 229 | +## Conclusion |
| 230 | + |
| 231 | +This PR lays the groundwork for modular, reusable command formatting across Forest CLI. The color system from `edges propose` is now available to all commands, enabling consistent, beautiful output with minimal code duplication. |
| 232 | + |
| 233 | +**Ready to use immediately!** Commands can start importing `colorize.*` functions today. |
| 234 | + |
| 235 | +Future phases will systematically migrate existing commands and extract core business logic, but this foundation is complete and ready for review. |
| 236 | + |
| 237 | +--- |
| 238 | + |
| 239 | +**PR Type**: Enhancement (Documentation + Infrastructure) |
| 240 | +**Breaking Changes**: None |
| 241 | +**Migration Required**: Optional (phased approach) |
| 242 | +**Dependencies**: chalk, @clack/prompts (already in use, now explicit) |
0 commit comments