workon 2.1.2 → 3.0.0
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 +19 -4
- package/bin/workon +1 -11
- package/dist/cli.js +2227 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +1216 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +280 -0
- package/dist/index.d.ts +280 -0
- package/dist/index.js +1173 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -21
- package/.claude/settings.local.json +0 -11
- package/.cursorindexingignore +0 -3
- package/.history/.gitignore_20250806202718 +0 -30
- package/.history/.gitignore_20250806231444 +0 -32
- package/.history/.gitignore_20250806231450 +0 -32
- package/.history/lib/tmux_20250806233103.js +0 -109
- package/.history/lib/tmux_20250806233219.js +0 -109
- package/.history/lib/tmux_20250806233223.js +0 -109
- package/.history/lib/tmux_20250806233230.js +0 -109
- package/.history/lib/tmux_20250806233231.js +0 -109
- package/.history/lib/tmux_20250807120751.js +0 -190
- package/.history/lib/tmux_20250807120757.js +0 -190
- package/.history/lib/tmux_20250807120802.js +0 -190
- package/.history/lib/tmux_20250807120808.js +0 -190
- package/.history/package_20250807114243.json +0 -43
- package/.history/package_20250807114257.json +0 -43
- package/.history/package_20250807114404.json +0 -43
- package/.history/package_20250807114409.json +0 -43
- package/.history/package_20250807114510.json +0 -43
- package/.history/package_20250807114637.json +0 -43
- package/.vscode/launch.json +0 -20
- package/.vscode/terminals.json +0 -11
- package/CHANGELOG.md +0 -103
- package/CLAUDE.md +0 -100
- package/cli/base.js +0 -16
- package/cli/config/index.js +0 -19
- package/cli/config/list.js +0 -26
- package/cli/config/set.js +0 -19
- package/cli/config/unset.js +0 -26
- package/cli/index.js +0 -184
- package/cli/interactive.js +0 -290
- package/cli/manage.js +0 -413
- package/cli/open.js +0 -414
- package/commands/base.js +0 -105
- package/commands/core/cwd/index.js +0 -86
- package/commands/core/ide/index.js +0 -84
- package/commands/core/web/index.js +0 -109
- package/commands/extensions/claude/index.js +0 -211
- package/commands/extensions/docker/index.js +0 -167
- package/commands/extensions/npm/index.js +0 -208
- package/commands/registry.js +0 -196
- package/demo-colon-syntax.js +0 -57
- package/docs/adr/001-command-centric-architecture.md +0 -304
- package/docs/adr/002-positional-command-arguments.md +0 -402
- package/docs/ideas.md +0 -93
- package/lib/config.js +0 -51
- package/lib/environment/base.js +0 -12
- package/lib/environment/index.js +0 -108
- package/lib/environment/project.js +0 -26
- package/lib/project.js +0 -68
- package/lib/tmux.js +0 -221
- package/lib/validation.js +0 -120
- package/test-architecture.js +0 -145
- package/test-colon-syntax.js +0 -85
- package/test-registry.js +0 -57
package/commands/registry.js
DELETED
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Command Registry for auto-discovery and management of commands
|
|
6
|
-
* Scans the commands directory and provides unified access to all commands
|
|
7
|
-
*/
|
|
8
|
-
class CommandRegistry {
|
|
9
|
-
constructor() {
|
|
10
|
-
this._commands = new Map();
|
|
11
|
-
this._initialized = false;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Initialize the registry by discovering all commands
|
|
16
|
-
*/
|
|
17
|
-
async initialize() {
|
|
18
|
-
if (this._initialized) return;
|
|
19
|
-
|
|
20
|
-
await this._discoverCommands();
|
|
21
|
-
this._initialized = true;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Discover commands from the commands directory
|
|
26
|
-
* @private
|
|
27
|
-
*/
|
|
28
|
-
async _discoverCommands() {
|
|
29
|
-
const commandsDir = path.join(__dirname);
|
|
30
|
-
|
|
31
|
-
// Discover core commands
|
|
32
|
-
await this._discoverCommandsInDirectory(path.join(commandsDir, 'core'));
|
|
33
|
-
|
|
34
|
-
// Discover extension commands
|
|
35
|
-
await this._discoverCommandsInDirectory(path.join(commandsDir, 'extensions'));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Discover commands in a specific directory
|
|
40
|
-
* @param {string} dir - Directory to scan
|
|
41
|
-
* @private
|
|
42
|
-
*/
|
|
43
|
-
async _discoverCommandsInDirectory(dir) {
|
|
44
|
-
if (!fs.existsSync(dir)) return;
|
|
45
|
-
|
|
46
|
-
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
47
|
-
|
|
48
|
-
for (const entry of entries) {
|
|
49
|
-
if (entry.isDirectory()) {
|
|
50
|
-
const commandDir = path.join(dir, entry.name);
|
|
51
|
-
const indexFile = path.join(commandDir, 'index.js');
|
|
52
|
-
|
|
53
|
-
if (fs.existsSync(indexFile)) {
|
|
54
|
-
try {
|
|
55
|
-
const CommandClass = require(indexFile);
|
|
56
|
-
|
|
57
|
-
// Validate command structure
|
|
58
|
-
if (this._isValidCommand(CommandClass)) {
|
|
59
|
-
const metadata = CommandClass.metadata;
|
|
60
|
-
this._commands.set(metadata.name, CommandClass);
|
|
61
|
-
} else {
|
|
62
|
-
console.error(`Invalid command structure in ${indexFile}`);
|
|
63
|
-
}
|
|
64
|
-
} catch (error) {
|
|
65
|
-
console.error(`Failed to load command from ${indexFile}:`, error.message);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Validate if a class is a proper command
|
|
74
|
-
* @param {Function} CommandClass - Command class to validate
|
|
75
|
-
* @returns {boolean}
|
|
76
|
-
* @private
|
|
77
|
-
*/
|
|
78
|
-
_isValidCommand(CommandClass) {
|
|
79
|
-
try {
|
|
80
|
-
// Check if it has required static properties
|
|
81
|
-
const metadata = CommandClass.metadata;
|
|
82
|
-
return metadata &&
|
|
83
|
-
typeof metadata.name === 'string' &&
|
|
84
|
-
typeof metadata.displayName === 'string' &&
|
|
85
|
-
typeof CommandClass.validation === 'object' &&
|
|
86
|
-
typeof CommandClass.configuration === 'object' &&
|
|
87
|
-
typeof CommandClass.processing === 'object';
|
|
88
|
-
} catch (error) {
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Get all valid event names from discovered commands
|
|
95
|
-
* @returns {string[]}
|
|
96
|
-
*/
|
|
97
|
-
getValidEventNames() {
|
|
98
|
-
this._ensureInitialized();
|
|
99
|
-
return Array.from(this._commands.keys());
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Get command by name
|
|
104
|
-
* @param {string} name - Command name
|
|
105
|
-
* @returns {Function|null} Command class or null if not found
|
|
106
|
-
*/
|
|
107
|
-
getCommandByName(name) {
|
|
108
|
-
this._ensureInitialized();
|
|
109
|
-
return this._commands.get(name) || null;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Get all commands for management UI
|
|
114
|
-
* @returns {Array<Object>} Array of command info objects
|
|
115
|
-
*/
|
|
116
|
-
getCommandsForManageUI() {
|
|
117
|
-
this._ensureInitialized();
|
|
118
|
-
|
|
119
|
-
const commands = [];
|
|
120
|
-
for (const [name, CommandClass] of this._commands) {
|
|
121
|
-
const metadata = CommandClass.metadata;
|
|
122
|
-
commands.push({
|
|
123
|
-
name: metadata.displayName,
|
|
124
|
-
value: name,
|
|
125
|
-
description: metadata.description
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
return commands.sort((a, b) => a.name.localeCompare(b.name));
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Get commands that support tmux integration
|
|
134
|
-
* @returns {Array<Object>} Array of commands with tmux support
|
|
135
|
-
*/
|
|
136
|
-
getTmuxEnabledCommands() {
|
|
137
|
-
this._ensureInitialized();
|
|
138
|
-
|
|
139
|
-
const tmuxCommands = [];
|
|
140
|
-
for (const [name, CommandClass] of this._commands) {
|
|
141
|
-
if (CommandClass.tmux) {
|
|
142
|
-
tmuxCommands.push({
|
|
143
|
-
name,
|
|
144
|
-
command: CommandClass,
|
|
145
|
-
priority: CommandClass.tmux.getLayoutPriority ? CommandClass.tmux.getLayoutPriority() : 0
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return tmuxCommands.sort((a, b) => b.priority - a.priority);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Get all available commands with their metadata
|
|
155
|
-
* @returns {Array<Object>} Array of command metadata
|
|
156
|
-
*/
|
|
157
|
-
getAllCommands() {
|
|
158
|
-
this._ensureInitialized();
|
|
159
|
-
|
|
160
|
-
const commands = [];
|
|
161
|
-
for (const [name, CommandClass] of this._commands) {
|
|
162
|
-
commands.push({
|
|
163
|
-
name,
|
|
164
|
-
metadata: CommandClass.metadata,
|
|
165
|
-
hasValidation: !!CommandClass.validation,
|
|
166
|
-
hasConfiguration: !!CommandClass.configuration,
|
|
167
|
-
hasProcessing: !!CommandClass.processing,
|
|
168
|
-
hasTmux: !!CommandClass.tmux,
|
|
169
|
-
hasHelp: !!CommandClass.help
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return commands;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Ensure registry is initialized
|
|
178
|
-
* @private
|
|
179
|
-
*/
|
|
180
|
-
_ensureInitialized() {
|
|
181
|
-
if (!this._initialized) {
|
|
182
|
-
throw new Error('CommandRegistry must be initialized before use. Call initialize() first.');
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Clear the registry (useful for testing)
|
|
188
|
-
*/
|
|
189
|
-
clear() {
|
|
190
|
-
this._commands.clear();
|
|
191
|
-
this._initialized = false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Export singleton instance
|
|
196
|
-
module.exports = new CommandRegistry();
|
package/demo-colon-syntax.js
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
console.log(`
|
|
4
|
-
🎯 COLON SYNTAX FEATURE DEMONSTRATION
|
|
5
|
-
=====================================
|
|
6
|
-
|
|
7
|
-
The new colon syntax allows selective command execution for projects:
|
|
8
|
-
|
|
9
|
-
📋 SYNTAX:
|
|
10
|
-
workon <project> # Execute all configured commands
|
|
11
|
-
workon <project>:<command> # Execute single command
|
|
12
|
-
workon <project>:<cmd1,cmd2> # Execute multiple commands
|
|
13
|
-
workon <project>:help # Show available commands
|
|
14
|
-
|
|
15
|
-
✨ KEY FEATURES:
|
|
16
|
-
|
|
17
|
-
1. BACKWARD COMPATIBLE
|
|
18
|
-
workon my-project # Still works exactly as before
|
|
19
|
-
|
|
20
|
-
2. SELECTIVE EXECUTION
|
|
21
|
-
workon my-project:cwd # Just change directory
|
|
22
|
-
workon my-project:claude # Just open Claude
|
|
23
|
-
|
|
24
|
-
3. SMART DEPENDENCIES
|
|
25
|
-
workon my-project:claude # Auto-adds 'cwd' dependency
|
|
26
|
-
workon my-project:npm # Auto-adds 'cwd' dependency
|
|
27
|
-
|
|
28
|
-
4. MULTIPLE COMMANDS
|
|
29
|
-
workon my-project:cwd,claude,npm # Custom combinations
|
|
30
|
-
|
|
31
|
-
5. PROJECT HELP
|
|
32
|
-
workon my-project:help # Show what commands are available
|
|
33
|
-
|
|
34
|
-
6. ERROR VALIDATION
|
|
35
|
-
workon my-project:invalid # Clear error messages
|
|
36
|
-
|
|
37
|
-
7. SHELL MODE SUPPORT
|
|
38
|
-
workon my-project:cwd --shell # Works with all flags
|
|
39
|
-
|
|
40
|
-
🏗️ IMPLEMENTATION HIGHLIGHTS:
|
|
41
|
-
|
|
42
|
-
• Zero switchit changes needed - uses existing parameter parsing
|
|
43
|
-
• Simple string split logic: project.split(':')
|
|
44
|
-
• Integrates perfectly with Command-Centric Architecture
|
|
45
|
-
• Smart layout detection works with any command combination
|
|
46
|
-
• Comprehensive validation and dependency resolution
|
|
47
|
-
|
|
48
|
-
🎉 BENEFITS:
|
|
49
|
-
|
|
50
|
-
• Faster startup for individual commands
|
|
51
|
-
• Flexible workflow matching
|
|
52
|
-
• Resource efficiency
|
|
53
|
-
• Better testing and debugging
|
|
54
|
-
• Foundation for future features (aliases, profiles, etc.)
|
|
55
|
-
|
|
56
|
-
This feature transforms workon from "all-or-nothing" to "pick-what-you-need"!
|
|
57
|
-
`);
|
|
@@ -1,304 +0,0 @@
|
|
|
1
|
-
# ADR-001: Command-Centric Architecture
|
|
2
|
-
|
|
3
|
-
**Status:** Implemented
|
|
4
|
-
**Date:** 2025-08-07
|
|
5
|
-
**Deciders:** Israel Roldan
|
|
6
|
-
|
|
7
|
-
## Context
|
|
8
|
-
|
|
9
|
-
The current architecture of the workon CLI has several maintainability issues:
|
|
10
|
-
|
|
11
|
-
### Current Problems
|
|
12
|
-
|
|
13
|
-
1. **Scattered Logic**: Command definitions, validation, help text, and processing logic are spread across multiple files
|
|
14
|
-
2. **Manual Maintenance**: Hardcoded lists in multiple locations require updates when adding new commands
|
|
15
|
-
3. **Tight Coupling**: Adding a new command requires touching 4-6 different files
|
|
16
|
-
4. **No Auto-Discovery**: System doesn't automatically detect available commands
|
|
17
|
-
5. **Inconsistent Patterns**: Different commands follow different implementation patterns
|
|
18
|
-
|
|
19
|
-
### Current Architecture Issues
|
|
20
|
-
|
|
21
|
-
When adding the NPM command, we had to modify:
|
|
22
|
-
- `lib/validation.js` - Add to valid events list + validation logic
|
|
23
|
-
- `cli/manage.js` - Add to event choices + configuration logic
|
|
24
|
-
- `cli/open.js` - Add event processing logic
|
|
25
|
-
- `lib/tmux.js` - Add layout management
|
|
26
|
-
- Multiple hardcoded arrays and switch statements
|
|
27
|
-
|
|
28
|
-
This creates:
|
|
29
|
-
- High cognitive load when adding features
|
|
30
|
-
- Risk of forgetting to update all locations
|
|
31
|
-
- Inconsistent user experience
|
|
32
|
-
- Difficult testing and debugging
|
|
33
|
-
|
|
34
|
-
## Decision
|
|
35
|
-
|
|
36
|
-
We will refactor to a **Command-Centric Architecture** where each command is self-contained and owns its complete lifecycle.
|
|
37
|
-
|
|
38
|
-
## Proposed Architecture
|
|
39
|
-
|
|
40
|
-
### 1. Directory Structure
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
commands/
|
|
44
|
-
├── core/ # Built-in system commands
|
|
45
|
-
│ ├── cwd/
|
|
46
|
-
│ │ ├── index.js # Main command class
|
|
47
|
-
│ │ ├── processing.js # Event processing logic
|
|
48
|
-
│ │ └── tmux.js # Tmux integration
|
|
49
|
-
│ ├── ide/
|
|
50
|
-
│ │ ├── index.js
|
|
51
|
-
│ │ ├── validation.js # IDE validation logic
|
|
52
|
-
│ │ └── processing.js
|
|
53
|
-
│ └── web/
|
|
54
|
-
│ ├── index.js
|
|
55
|
-
│ ├── validation.js
|
|
56
|
-
│ └── processing.js
|
|
57
|
-
├── extensions/ # Feature-rich commands
|
|
58
|
-
│ ├── claude/
|
|
59
|
-
│ │ ├── index.js
|
|
60
|
-
│ │ ├── validation.js # Claude config validation
|
|
61
|
-
│ │ ├── configuration.js # Interactive setup
|
|
62
|
-
│ │ ├── processing.js # Event processing
|
|
63
|
-
│ │ └── tmux.js # Split terminal logic
|
|
64
|
-
│ └── npm/
|
|
65
|
-
│ ├── index.js
|
|
66
|
-
│ ├── validation.js # NPM config validation
|
|
67
|
-
│ ├── configuration.js # Interactive setup
|
|
68
|
-
│ ├── processing.js # Event processing
|
|
69
|
-
│ └── tmux.js # Multi-pane layouts
|
|
70
|
-
└── registry.js # Auto-discovery system
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### 2. Command Interface
|
|
74
|
-
|
|
75
|
-
Each command implements a standardized interface:
|
|
76
|
-
|
|
77
|
-
```javascript
|
|
78
|
-
// commands/extensions/npm/index.js
|
|
79
|
-
class NPMCommand {
|
|
80
|
-
static metadata = {
|
|
81
|
-
name: 'npm',
|
|
82
|
-
displayName: 'Run NPM command',
|
|
83
|
-
description: 'Execute NPM scripts in project directory',
|
|
84
|
-
category: 'development',
|
|
85
|
-
requiresTmux: true,
|
|
86
|
-
dependencies: ['npm']
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
static validation = {
|
|
90
|
-
// Command-specific validation
|
|
91
|
-
validateConfig(config) { /* ... */ }
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
static configuration = {
|
|
95
|
-
// Interactive setup prompts
|
|
96
|
-
async configureInteractive() { /* ... */ },
|
|
97
|
-
getDefaultConfig() { /* ... */ }
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
static processing = {
|
|
101
|
-
// Event processing
|
|
102
|
-
async processEvent(context) { /* ... */ },
|
|
103
|
-
generateShellCommand(context) { /* ... */ }
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
static tmux = {
|
|
107
|
-
// Tmux layout contributions
|
|
108
|
-
getLayoutPriority() { return 10; },
|
|
109
|
-
contributeToLayout(existingCommands) { /* ... */ }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
static help = {
|
|
113
|
-
usage: 'npm: <script-name>',
|
|
114
|
-
examples: [
|
|
115
|
-
{ config: 'npm: "dev"', description: 'Run npm run dev' },
|
|
116
|
-
{ config: 'npm: { command: "test", watch: true }', description: 'Run tests in watch mode' }
|
|
117
|
-
]
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### 3. Auto-Discovery System
|
|
123
|
-
|
|
124
|
-
```javascript
|
|
125
|
-
// commands/registry.js
|
|
126
|
-
class CommandRegistry {
|
|
127
|
-
static async discoverCommands() {
|
|
128
|
-
// Scan commands/ directory
|
|
129
|
-
// Load command classes
|
|
130
|
-
// Build registry of available commands
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
static getValidEventNames() {
|
|
134
|
-
// Auto-generate from discovered commands
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
static getCommandByName(name) {
|
|
138
|
-
// Lookup command instance
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
static getCommandsForManageUI() {
|
|
142
|
-
// Get display info for interactive management
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
### 4. Integration Points
|
|
148
|
-
|
|
149
|
-
#### Validation System
|
|
150
|
-
```javascript
|
|
151
|
-
// lib/validation.js (simplified)
|
|
152
|
-
class ProjectValidator {
|
|
153
|
-
validateEvents(events) {
|
|
154
|
-
const validCommands = CommandRegistry.getValidEventNames();
|
|
155
|
-
// Delegate to command-specific validation
|
|
156
|
-
for (const [eventName, config] of Object.entries(events)) {
|
|
157
|
-
const command = CommandRegistry.getCommandByName(eventName);
|
|
158
|
-
if (command) {
|
|
159
|
-
const result = command.validation.validateConfig(config);
|
|
160
|
-
if (result !== true) return result;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
#### Interactive Management
|
|
168
|
-
```javascript
|
|
169
|
-
// cli/manage.js (simplified)
|
|
170
|
-
class manage extends command {
|
|
171
|
-
async getEventChoices() {
|
|
172
|
-
return CommandRegistry.getCommandsForManageUI();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async configureEvent(eventName) {
|
|
176
|
-
const command = CommandRegistry.getCommandByName(eventName);
|
|
177
|
-
return await command.configuration.configureInteractive();
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
#### Event Processing
|
|
183
|
-
```javascript
|
|
184
|
-
// cli/open.js (simplified)
|
|
185
|
-
class open extends command {
|
|
186
|
-
async processEvent(eventName, project, context) {
|
|
187
|
-
const command = CommandRegistry.getCommandByName(eventName);
|
|
188
|
-
return await command.processing.processEvent({
|
|
189
|
-
project,
|
|
190
|
-
isShellMode: context.isShellMode,
|
|
191
|
-
shellCommands: context.shellCommands
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### 5. Tmux Layout System
|
|
198
|
-
|
|
199
|
-
Commands can contribute to tmux layouts with priority-based composition:
|
|
200
|
-
|
|
201
|
-
```javascript
|
|
202
|
-
// Smart layout detection
|
|
203
|
-
const enabledCommands = getEnabledCommands(project);
|
|
204
|
-
const tmuxContributors = enabledCommands
|
|
205
|
-
.filter(cmd => cmd.tmux)
|
|
206
|
-
.sort((a, b) => b.tmux.getLayoutPriority() - a.tmux.getLayoutPriority());
|
|
207
|
-
|
|
208
|
-
const layout = tmuxContributors[0].tmux.contributeToLayout(enabledCommands);
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
## Implementation Plan
|
|
212
|
-
|
|
213
|
-
### Phase 1: Foundation
|
|
214
|
-
1. Create `commands/` directory structure
|
|
215
|
-
2. Implement `CommandRegistry` with auto-discovery
|
|
216
|
-
3. Create base command interface/abstract class
|
|
217
|
-
4. Add command loading and registration system
|
|
218
|
-
|
|
219
|
-
### Phase 2: Core Command Migration
|
|
220
|
-
1. Extract `cwd` command to `commands/core/cwd/`
|
|
221
|
-
2. Extract `ide` command to `commands/core/ide/`
|
|
222
|
-
3. Extract `web` command to `commands/core/web/`
|
|
223
|
-
4. Update validation system to use registry
|
|
224
|
-
|
|
225
|
-
### Phase 3: Extension Command Migration
|
|
226
|
-
1. Extract `claude` command to `commands/extensions/claude/`
|
|
227
|
-
2. Extract `npm` command to `commands/extensions/npm/`
|
|
228
|
-
3. Update interactive management to use command definitions
|
|
229
|
-
4. Update event processing to use command registry
|
|
230
|
-
|
|
231
|
-
### Phase 4: Enhanced Features
|
|
232
|
-
1. Add command dependency checking
|
|
233
|
-
2. Implement plugin-like command loading
|
|
234
|
-
3. Add command-specific help system
|
|
235
|
-
4. Add command testing framework
|
|
236
|
-
|
|
237
|
-
### Phase 5: Advanced Tmux Integration
|
|
238
|
-
1. Implement priority-based layout composition
|
|
239
|
-
2. Add layout conflict resolution
|
|
240
|
-
3. Add custom layout definitions per command
|
|
241
|
-
4. Add layout preview/testing
|
|
242
|
-
|
|
243
|
-
## Benefits
|
|
244
|
-
|
|
245
|
-
### For Developers
|
|
246
|
-
- **Single Responsibility**: Each command owns its complete lifecycle
|
|
247
|
-
- **Easy Testing**: Isolated command logic with clear interfaces
|
|
248
|
-
- **Plugin Architecture**: Easy to add/remove commands
|
|
249
|
-
- **Better Organization**: Everything related to a command in one place
|
|
250
|
-
- **Reduced Coupling**: Commands don't need to know about each other
|
|
251
|
-
|
|
252
|
-
### For Users
|
|
253
|
-
- **Consistent Experience**: All commands follow same patterns
|
|
254
|
-
- **Better Help**: Command-specific documentation and examples
|
|
255
|
-
- **Auto-Discovery**: New commands automatically available
|
|
256
|
-
- **Extensibility**: Easy to add custom commands
|
|
257
|
-
|
|
258
|
-
### For Maintenance
|
|
259
|
-
- **No More Hardcoded Lists**: Commands auto-register themselves
|
|
260
|
-
- **Easier Debugging**: Clear command boundaries
|
|
261
|
-
- **Simpler Refactoring**: Changes contained within command scope
|
|
262
|
-
- **Better Documentation**: Command documentation co-located with code
|
|
263
|
-
|
|
264
|
-
## Risks and Mitigations
|
|
265
|
-
|
|
266
|
-
### Risk: Increased Complexity
|
|
267
|
-
**Mitigation**: Provide clear base classes and documentation. Start with simple commands.
|
|
268
|
-
|
|
269
|
-
### Risk: Performance Impact
|
|
270
|
-
**Mitigation**: Lazy loading of commands. Cache registry after initial discovery.
|
|
271
|
-
|
|
272
|
-
### Risk: Breaking Changes
|
|
273
|
-
**Mitigation**: Implement alongside existing system. Gradual migration path.
|
|
274
|
-
|
|
275
|
-
### Risk: Over-Engineering
|
|
276
|
-
**Mitigation**: Start simple. Add complexity only when needed. Focus on current pain points.
|
|
277
|
-
|
|
278
|
-
## Success Criteria
|
|
279
|
-
|
|
280
|
-
1. Adding a new command requires touching only files in that command's directory
|
|
281
|
-
2. Command validation, configuration, and processing logic is co-located
|
|
282
|
-
3. Interactive management automatically discovers and presents new commands
|
|
283
|
-
4. Tmux layouts compose automatically based on enabled commands
|
|
284
|
-
5. Help system provides command-specific guidance
|
|
285
|
-
6. Testing can be done per-command with clear interfaces
|
|
286
|
-
|
|
287
|
-
## Alternative Considered
|
|
288
|
-
|
|
289
|
-
### Plugin System with External Commands
|
|
290
|
-
- **Pros**: Ultimate flexibility, true plugin architecture
|
|
291
|
-
- **Cons**: Complexity of plugin loading, versioning, security concerns
|
|
292
|
-
- **Decision**: Too complex for current needs. Start with internal command structure.
|
|
293
|
-
|
|
294
|
-
### Monolithic Command Classes
|
|
295
|
-
- **Pros**: Single file per command
|
|
296
|
-
- **Cons**: Large files, harder to test specific aspects
|
|
297
|
-
- **Decision**: Multi-file approach provides better separation of concerns.
|
|
298
|
-
|
|
299
|
-
## References
|
|
300
|
-
|
|
301
|
-
- Current architecture pain points identified during NPM command implementation
|
|
302
|
-
- Command pattern design principles
|
|
303
|
-
- Plugin architecture best practices
|
|
304
|
-
- CLI framework patterns (e.g., Angular CLI, Vue CLI command structures)
|