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
|
@@ -1,402 +0,0 @@
|
|
|
1
|
-
# ADR-002: Positional Command Arguments
|
|
2
|
-
|
|
3
|
-
**Status:** Implemented (as Colon Syntax)
|
|
4
|
-
**Date:** 2025-08-07
|
|
5
|
-
**Deciders:** Israel Roldan
|
|
6
|
-
**Related:** ADR-001 (Command-Centric Architecture)
|
|
7
|
-
|
|
8
|
-
**Implementation Note:** Instead of positional arguments, we implemented a cleaner colon syntax approach:
|
|
9
|
-
- `workon project` - Execute all commands
|
|
10
|
-
- `workon project:cwd` - Execute single command
|
|
11
|
-
- `workon project:cwd,claude` - Execute multiple commands
|
|
12
|
-
- `workon project:help` - Show available commands
|
|
13
|
-
|
|
14
|
-
## Context
|
|
15
|
-
|
|
16
|
-
Currently, the workon CLI operates with a "all-or-nothing" approach where running `workon my-project` executes all configured events for that project. However, there are scenarios where users want to execute only specific commands for a project.
|
|
17
|
-
|
|
18
|
-
### Current Behavior
|
|
19
|
-
```bash
|
|
20
|
-
workon my-project # Executes ALL configured events (cwd, ide, claude, npm, etc.)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Desired Behavior
|
|
24
|
-
```bash
|
|
25
|
-
workon my-project # Executes all configured events (current behavior)
|
|
26
|
-
workon my-project cwd # Only changes to project directory
|
|
27
|
-
workon my-project claude # Only opens Claude in project directory
|
|
28
|
-
workon my-project npm # Only runs npm command
|
|
29
|
-
workon my-project cwd claude # Runs cwd + claude (split terminal)
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Problems with Current Approach
|
|
33
|
-
|
|
34
|
-
1. **Inflexibility**: Can't run individual commands without modifying project configuration
|
|
35
|
-
2. **Performance**: Sometimes you don't want to start dev server, just open Claude
|
|
36
|
-
3. **Workflow Mismatch**: Different workflows need different command combinations
|
|
37
|
-
4. **Resource Usage**: Starting all services when you only need one is wasteful
|
|
38
|
-
|
|
39
|
-
### Common Use Cases
|
|
40
|
-
|
|
41
|
-
- **Quick directory change**: `workon my-project cwd`
|
|
42
|
-
- **AI assistance only**: `workon my-project claude`
|
|
43
|
-
- **Development startup**: `workon my-project cwd claude npm`
|
|
44
|
-
- **IDE-only launch**: `workon my-project ide`
|
|
45
|
-
- **Terminal + build**: `workon my-project cwd npm`
|
|
46
|
-
|
|
47
|
-
## Decision
|
|
48
|
-
|
|
49
|
-
Implement **positional command arguments** that allow users to specify which commands to execute for a project, while maintaining backward compatibility with the current "execute all" behavior.
|
|
50
|
-
|
|
51
|
-
## Proposed Implementation
|
|
52
|
-
|
|
53
|
-
### 1. CLI Argument Structure
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
workon <project> [command1] [command2] [...commandN] [options]
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
**Examples:**
|
|
60
|
-
```bash
|
|
61
|
-
workon my-project # All configured events
|
|
62
|
-
workon my-project cwd # Just directory change
|
|
63
|
-
workon my-project claude # Just Claude
|
|
64
|
-
workon my-project cwd claude # Directory + Claude
|
|
65
|
-
workon my-project cwd claude npm # Full development setup
|
|
66
|
-
workon my-project ide --shell # IDE with shell output
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 2. Argument Parsing Logic
|
|
70
|
-
|
|
71
|
-
```javascript
|
|
72
|
-
// Enhanced argument parsing
|
|
73
|
-
class ProjectArgumentParser {
|
|
74
|
-
static parse(args) {
|
|
75
|
-
const projectName = args[0];
|
|
76
|
-
const commands = args.slice(1).filter(arg => !arg.startsWith('--'));
|
|
77
|
-
const flags = args.slice(1).filter(arg => arg.startsWith('--'));
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
projectName,
|
|
81
|
-
commands: commands.length > 0 ? commands : null, // null means "all configured"
|
|
82
|
-
flags
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static validate(projectName, commands, projectConfig) {
|
|
87
|
-
// Validate that requested commands are configured for the project
|
|
88
|
-
const configuredEvents = Object.keys(projectConfig.events || {});
|
|
89
|
-
const invalidCommands = commands.filter(cmd => !configuredEvents.includes(cmd));
|
|
90
|
-
|
|
91
|
-
if (invalidCommands.length > 0) {
|
|
92
|
-
throw new Error(`Commands not configured for project '${projectName}': ${invalidCommands.join(', ')}`);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
### 3. Execution Logic
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
// cli/open.js - Enhanced execution
|
|
102
|
-
class open extends command {
|
|
103
|
-
async processProject(project, requestedCommands = null) {
|
|
104
|
-
const projectConfig = this.getProjectConfig(project);
|
|
105
|
-
const configuredEvents = Object.keys(projectConfig.events || {});
|
|
106
|
-
|
|
107
|
-
// Determine which events to execute
|
|
108
|
-
let eventsToExecute;
|
|
109
|
-
if (requestedCommands) {
|
|
110
|
-
// Validate requested commands are configured
|
|
111
|
-
this.validateRequestedCommands(requestedCommands, configuredEvents, project);
|
|
112
|
-
eventsToExecute = requestedCommands;
|
|
113
|
-
} else {
|
|
114
|
-
// Execute all configured events (current behavior)
|
|
115
|
-
eventsToExecute = configuredEvents.filter(e => projectConfig.events[e]);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
await this.executeEvents(projectConfig, eventsToExecute);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
validateRequestedCommands(requested, configured, projectName) {
|
|
122
|
-
const invalid = requested.filter(cmd => !configured.includes(cmd));
|
|
123
|
-
if (invalid.length > 0) {
|
|
124
|
-
throw new Error(
|
|
125
|
-
`Commands not configured for project '${projectName}': ${invalid.join(', ')}\n` +
|
|
126
|
-
`Available commands: ${configured.join(', ')}`
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### 4. Smart Layout Detection
|
|
134
|
-
|
|
135
|
-
The intelligent layout detection from ADR-001 would work with positional arguments:
|
|
136
|
-
|
|
137
|
-
```javascript
|
|
138
|
-
// Layout detection based on actual commands being executed
|
|
139
|
-
const layoutDetection = {
|
|
140
|
-
determineLayout(executedCommands, projectConfig) {
|
|
141
|
-
const hasCwd = executedCommands.includes('cwd');
|
|
142
|
-
const hasClaude = executedCommands.includes('claude');
|
|
143
|
-
const hasNpm = executedCommands.includes('npm');
|
|
144
|
-
|
|
145
|
-
if (hasCwd && hasClaude && hasNpm) {
|
|
146
|
-
return 'three-pane'; // Claude + Terminal + NPM
|
|
147
|
-
} else if (hasCwd && hasNpm) {
|
|
148
|
-
return 'two-pane-npm'; // Terminal + NPM
|
|
149
|
-
} else if (hasCwd && hasClaude) {
|
|
150
|
-
return 'two-pane-claude'; // Claude + Terminal
|
|
151
|
-
} else {
|
|
152
|
-
return 'individual'; // Execute commands individually
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
};
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### 5. Help and Discovery
|
|
159
|
-
|
|
160
|
-
Enhanced help system that shows available commands per project:
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
workon my-project --help
|
|
164
|
-
# Output:
|
|
165
|
-
# Available commands for 'my-project':
|
|
166
|
-
# cwd - Change to project directory
|
|
167
|
-
# claude - Open Claude Code with --resume flag
|
|
168
|
-
# npm - Run 'npm run dev'
|
|
169
|
-
# ide - Open in VS Code
|
|
170
|
-
#
|
|
171
|
-
# Usage:
|
|
172
|
-
# workon my-project [command1] [command2] ...
|
|
173
|
-
#
|
|
174
|
-
# Examples:
|
|
175
|
-
# workon my-project cwd claude # Split terminal with Claude
|
|
176
|
-
# workon my-project npm # Just start dev server
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
## Integration with ADR-001
|
|
180
|
-
|
|
181
|
-
This feature complements the Command-Centric Architecture:
|
|
182
|
-
|
|
183
|
-
### Command Interface Extension
|
|
184
|
-
```javascript
|
|
185
|
-
class NPMCommand {
|
|
186
|
-
static metadata = {
|
|
187
|
-
name: 'npm',
|
|
188
|
-
displayName: 'Run NPM command',
|
|
189
|
-
canRunIndividually: true, // Can be executed alone
|
|
190
|
-
requiresProject: true, // Needs project context
|
|
191
|
-
dependencies: ['npm']
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
static help = {
|
|
195
|
-
shortDescription: 'Run npm scripts',
|
|
196
|
-
individualUsage: 'workon <project> npm',
|
|
197
|
-
examples: [
|
|
198
|
-
'workon my-app npm # Run configured npm script',
|
|
199
|
-
'workon my-app cwd npm # Terminal + npm in split'
|
|
200
|
-
]
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### Enhanced Command Registry
|
|
206
|
-
```javascript
|
|
207
|
-
class CommandRegistry {
|
|
208
|
-
static getAvailableCommandsForProject(projectConfig) {
|
|
209
|
-
const configuredEvents = Object.keys(projectConfig.events || {});
|
|
210
|
-
return configuredEvents.map(eventName => {
|
|
211
|
-
const command = this.getCommandByName(eventName);
|
|
212
|
-
return {
|
|
213
|
-
name: eventName,
|
|
214
|
-
description: command.metadata.displayName,
|
|
215
|
-
canRunIndividually: command.metadata.canRunIndividually
|
|
216
|
-
};
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
## Implementation Challenges
|
|
223
|
-
|
|
224
|
-
### 1. Argument Parsing Complexity
|
|
225
|
-
**Challenge**: Distinguishing between project names and commands
|
|
226
|
-
```bash
|
|
227
|
-
workon claude my-project # Project named 'claude' or command 'claude' on 'my-project'?
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
**Solution**: Commands are always positional after project name:
|
|
231
|
-
```bash
|
|
232
|
-
workon my-project claude # ✅ Clear: project 'my-project', command 'claude'
|
|
233
|
-
workon claude # ✅ Clear: project 'claude', no specific commands
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### 2. Command Validation
|
|
237
|
-
**Challenge**: What if user requests a command that's not configured?
|
|
238
|
-
|
|
239
|
-
**Options:**
|
|
240
|
-
- **Strict**: Error if command not configured
|
|
241
|
-
- **Permissive**: Execute if command exists, ignore configuration
|
|
242
|
-
- **Hybrid**: Warn but execute if possible
|
|
243
|
-
|
|
244
|
-
**Recommendation**: Start strict, add permissive mode with flag later.
|
|
245
|
-
|
|
246
|
-
### 3. Backward Compatibility
|
|
247
|
-
**Challenge**: Ensure existing usage patterns continue to work
|
|
248
|
-
|
|
249
|
-
**Solution**: No commands specified = execute all (current behavior)
|
|
250
|
-
```bash
|
|
251
|
-
workon my-project # Still works as before
|
|
252
|
-
workon my-project --shell # Still works as before
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### 4. Complex Command Interactions
|
|
256
|
-
**Challenge**: Some commands have dependencies or conflicts
|
|
257
|
-
|
|
258
|
-
**Examples:**
|
|
259
|
-
- `claude` without `cwd` - should we auto-add `cwd`?
|
|
260
|
-
- `npm` without `cwd` - doesn't make sense
|
|
261
|
-
|
|
262
|
-
**Solution**: Command dependency resolution:
|
|
263
|
-
```javascript
|
|
264
|
-
class CommandDependencyResolver {
|
|
265
|
-
static resolve(requestedCommands, projectConfig) {
|
|
266
|
-
const resolved = [...requestedCommands];
|
|
267
|
-
|
|
268
|
-
// Auto-add dependencies
|
|
269
|
-
if (requestedCommands.includes('npm') && !requestedCommands.includes('cwd')) {
|
|
270
|
-
resolved.unshift('cwd'); // npm needs cwd
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (requestedCommands.includes('claude') && !requestedCommands.includes('cwd')) {
|
|
274
|
-
resolved.unshift('cwd'); // claude needs cwd
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
return resolved;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
## User Experience Design
|
|
283
|
-
|
|
284
|
-
### 1. Intuitive Command Discovery
|
|
285
|
-
```bash
|
|
286
|
-
workon my-project help # Show available commands for this project
|
|
287
|
-
workon help commands # Show all available command types
|
|
288
|
-
workon --list-projects # Show all projects with their commands
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
### 2. Smart Defaults
|
|
292
|
-
```bash
|
|
293
|
-
workon my-project claude # Automatically includes 'cwd' dependency
|
|
294
|
-
workon my-project npm # Automatically includes 'cwd' dependency
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### 3. Error Messages
|
|
298
|
-
```bash
|
|
299
|
-
workon my-project invalid-cmd
|
|
300
|
-
# Error: Command 'invalid-cmd' not configured for project 'my-project'
|
|
301
|
-
# Available commands: cwd, claude, npm, ide
|
|
302
|
-
#
|
|
303
|
-
# Tip: Run 'workon my-project help' for more details
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
## Implementation Plan
|
|
307
|
-
|
|
308
|
-
### Phase 1: Argument Parsing Foundation
|
|
309
|
-
1. Implement `ProjectArgumentParser` class
|
|
310
|
-
2. Update CLI entry point to handle positional arguments
|
|
311
|
-
3. Add backward compatibility tests
|
|
312
|
-
4. Basic command validation
|
|
313
|
-
|
|
314
|
-
### Phase 2: Command Execution Logic
|
|
315
|
-
1. Update `open.js` to handle selective command execution
|
|
316
|
-
2. Implement dependency resolution system
|
|
317
|
-
3. Add error handling and user-friendly messages
|
|
318
|
-
4. Update help system
|
|
319
|
-
|
|
320
|
-
### Phase 3: Layout Integration
|
|
321
|
-
1. Update smart layout detection for positional commands
|
|
322
|
-
2. Ensure tmux layouts work with partial command sets
|
|
323
|
-
3. Add fallback behavior for unsupported combinations
|
|
324
|
-
|
|
325
|
-
### Phase 4: Enhanced UX
|
|
326
|
-
1. Add command discovery helpers
|
|
327
|
-
2. Implement auto-completion support
|
|
328
|
-
3. Add command validation with helpful suggestions
|
|
329
|
-
4. Enhanced help and documentation
|
|
330
|
-
|
|
331
|
-
## Success Criteria
|
|
332
|
-
|
|
333
|
-
1. **Backward Compatibility**: `workon my-project` works exactly as before
|
|
334
|
-
2. **Individual Commands**: `workon my-project cwd` only changes directory
|
|
335
|
-
3. **Command Combinations**: `workon my-project cwd claude` creates split terminal
|
|
336
|
-
4. **Error Handling**: Clear messages for invalid command combinations
|
|
337
|
-
5. **Help System**: Users can discover available commands per project
|
|
338
|
-
6. **Performance**: Single commands execute faster than full project setup
|
|
339
|
-
|
|
340
|
-
## Examples
|
|
341
|
-
|
|
342
|
-
### Basic Usage
|
|
343
|
-
```bash
|
|
344
|
-
# Current behavior preserved
|
|
345
|
-
workon my-app # All configured events
|
|
346
|
-
|
|
347
|
-
# New individual command usage
|
|
348
|
-
workon my-app cwd # Just cd to directory
|
|
349
|
-
workon my-app claude # Just open Claude (with auto cwd)
|
|
350
|
-
workon my-app ide # Just open IDE
|
|
351
|
-
workon my-app npm # Just run npm script (with auto cwd)
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### Advanced Combinations
|
|
355
|
-
```bash
|
|
356
|
-
# Custom combinations
|
|
357
|
-
workon my-app cwd claude # Split terminal: Claude + shell
|
|
358
|
-
workon my-app cwd npm # Split terminal: shell + npm
|
|
359
|
-
workon my-app cwd claude npm # Three-pane: Claude + shell + npm
|
|
360
|
-
workon my-app ide claude # IDE + Claude (no terminal)
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
### Shell Mode
|
|
364
|
-
```bash
|
|
365
|
-
# Shell mode with positional args
|
|
366
|
-
workon my-app cwd --shell # Just outputs: cd "/path/to/project"
|
|
367
|
-
workon my-app cwd claude --shell # Outputs tmux split commands
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
## Benefits
|
|
371
|
-
|
|
372
|
-
### For Users
|
|
373
|
-
- **Flexibility**: Run only what you need
|
|
374
|
-
- **Performance**: Faster startup for individual commands
|
|
375
|
-
- **Workflow Optimization**: Match commands to specific use cases
|
|
376
|
-
- **Resource Efficiency**: Don't start unnecessary services
|
|
377
|
-
|
|
378
|
-
### For Development
|
|
379
|
-
- **Testing**: Easier to test individual commands
|
|
380
|
-
- **Debugging**: Isolate issues to specific commands
|
|
381
|
-
- **Modularity**: Commands become more independent
|
|
382
|
-
|
|
383
|
-
### For Future Features
|
|
384
|
-
- **Command Aliases**: `workon my-app dev` → `workon my-app cwd claude npm`
|
|
385
|
-
- **Profiles**: Save common command combinations
|
|
386
|
-
- **Conditional Logic**: Run commands based on project state
|
|
387
|
-
|
|
388
|
-
## Risks and Mitigations
|
|
389
|
-
|
|
390
|
-
### Risk: User Confusion
|
|
391
|
-
**Mitigation**: Clear documentation, intuitive defaults, helpful error messages
|
|
392
|
-
|
|
393
|
-
### Risk: Complex Dependency Resolution
|
|
394
|
-
**Mitigation**: Start simple, add complexity incrementally, clear logging
|
|
395
|
-
|
|
396
|
-
### Risk: Breaking Changes
|
|
397
|
-
**Mitigation**: Maintain backward compatibility, opt-in behavior
|
|
398
|
-
|
|
399
|
-
### Risk: Command Conflicts
|
|
400
|
-
**Mitigation**: Define clear command interaction rules, validation system
|
|
401
|
-
|
|
402
|
-
This ADR provides a comprehensive plan for adding positional command arguments while maintaining the project's usability and setting the foundation for even more flexible workflow management.
|
package/docs/ideas.md
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
# Ideas for workon
|
|
2
|
-
|
|
3
|
-
This document contains ideas for future enhancements to the workon project.
|
|
4
|
-
|
|
5
|
-
## NPM Command Integration
|
|
6
|
-
|
|
7
|
-
### Three-Pane Development Layout
|
|
8
|
-
When `cwd`, `claude`, and `npm` events are enabled, create a three-pane tmux layout:
|
|
9
|
-
- **Left pane**: Claude Code running in project directory (full height)
|
|
10
|
-
- **Top-right pane**: Shell terminal in project directory
|
|
11
|
-
- **Bottom-right pane**: NPM command running (e.g., `npm run dev`, `npm test`)
|
|
12
|
-
|
|
13
|
-
**Implementation approach:**
|
|
14
|
-
- Extend current split terminal to support three panes
|
|
15
|
-
- Create initial vertical split (Claude | Terminal)
|
|
16
|
-
- Split the right terminal pane horizontally (Terminal | npm)
|
|
17
|
-
- Use tmux: `split-window -v` on the right pane
|
|
18
|
-
- Auto-run specified npm command in bottom-right pane
|
|
19
|
-
|
|
20
|
-
**Configuration:**
|
|
21
|
-
```json
|
|
22
|
-
{
|
|
23
|
-
"events": {
|
|
24
|
-
"cwd": "true",
|
|
25
|
-
"claude": {
|
|
26
|
-
"flags": ["--resume"],
|
|
27
|
-
"split_terminal": true
|
|
28
|
-
},
|
|
29
|
-
"npm": "dev"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**Alternative configuration:**
|
|
35
|
-
```json
|
|
36
|
-
{
|
|
37
|
-
"events": {
|
|
38
|
-
"cwd": "true",
|
|
39
|
-
"claude": "true",
|
|
40
|
-
"npm": {
|
|
41
|
-
"command": "dev",
|
|
42
|
-
"watch": true,
|
|
43
|
-
"auto_restart": false
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
**Benefits:**
|
|
50
|
-
- Complete development environment in one tmux session
|
|
51
|
-
- Claude AI + Terminal + Development server all visible
|
|
52
|
-
- Perfect for web development workflows
|
|
53
|
-
- Automatic npm script execution
|
|
54
|
-
|
|
55
|
-
**Tmux Layout:**
|
|
56
|
-
```
|
|
57
|
-
┌──────────────┬──────────────┐
|
|
58
|
-
│ │ Terminal │
|
|
59
|
-
│ Claude ├──────────────┤
|
|
60
|
-
│ (full │ npm run dev │
|
|
61
|
-
│ height) │ │
|
|
62
|
-
└──────────────┴──────────────┘
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Two-Pane Terminal + NPM Layout
|
|
66
|
-
When `cwd` and `npm` events are enabled (without Claude), create a two-pane tmux layout:
|
|
67
|
-
- **Left pane**: Shell terminal in project directory
|
|
68
|
-
- **Right pane**: NPM command running (e.g., `npm run dev`, `npm test`)
|
|
69
|
-
|
|
70
|
-
**Tmux Layout:**
|
|
71
|
-
```
|
|
72
|
-
┌──────────────┬──────────────┐
|
|
73
|
-
│ │ │
|
|
74
|
-
│ Terminal │ npm run dev │
|
|
75
|
-
│ │ │
|
|
76
|
-
│ │ │
|
|
77
|
-
└──────────────┴──────────────┘
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**Use cases:**
|
|
81
|
-
- Traditional development workflow without AI assistance
|
|
82
|
-
- Monitoring build output while running commands
|
|
83
|
-
- Side-by-side terminal and dev server
|
|
84
|
-
|
|
85
|
-
## Future Ideas
|
|
86
|
-
|
|
87
|
-
### Auto-enable Split Terminal
|
|
88
|
-
When both `cwd` and `claude` events are enabled, automatically enable split terminal mode without requiring explicit configuration.
|
|
89
|
-
|
|
90
|
-
### Project Templates
|
|
91
|
-
Pre-configured project templates for common development stacks (React, Node.js, Python, etc.) with appropriate events and npm commands.
|
|
92
|
-
|
|
93
|
-
*Add more ideas here as they come up...*
|
package/lib/config.js
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
const Conf = require('conf');
|
|
2
|
-
|
|
3
|
-
class Config {
|
|
4
|
-
constructor () {
|
|
5
|
-
this._transient = {};
|
|
6
|
-
this._store = new Conf({
|
|
7
|
-
projectName: Config.projectName,
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
get (key, defaultValue) {
|
|
12
|
-
if (Config.transientProps.indexOf(key.split('.')[0]) > -1) {
|
|
13
|
-
return this._transient[key] || defaultValue;
|
|
14
|
-
} else {
|
|
15
|
-
return this._store.get(key, defaultValue);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
set (key, value) {
|
|
20
|
-
if (!value) {
|
|
21
|
-
this._store.set(key);
|
|
22
|
-
} else {
|
|
23
|
-
if (Config.transientProps.indexOf(key.split('.')[0]) > -1) {
|
|
24
|
-
this._transient[key] = value;
|
|
25
|
-
} else {
|
|
26
|
-
this._store.set(key, value);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
has (key) {
|
|
32
|
-
if (Config.transientProps.indexOf(key.split('.')[0]) > -1) {
|
|
33
|
-
return this._transient.hasOwnProperty(key);
|
|
34
|
-
} else {
|
|
35
|
-
return this._store.has(key);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
delete (key) {
|
|
40
|
-
if (Config.transientProps.indexOf(key.split('.')[0]) > -1) {
|
|
41
|
-
delete this._transient[key];
|
|
42
|
-
} else {
|
|
43
|
-
this._store.delete(key);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
Config.projectName = 'workon';
|
|
49
|
-
Config.transientProps = ['pkg', 'work'];
|
|
50
|
-
|
|
51
|
-
module.exports = Config;
|
package/lib/environment/base.js
DELETED
package/lib/environment/index.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
const Environment = require('./base');
|
|
2
|
-
const ProjectEnvironment = require('./project');
|
|
3
|
-
const Config = require('../config');
|
|
4
|
-
const File = require('phylo');
|
|
5
|
-
const loog = require('loog');
|
|
6
|
-
const git = require('simple-git');
|
|
7
|
-
|
|
8
|
-
class EnvironmentRecognizer {
|
|
9
|
-
static configure (config, log) {
|
|
10
|
-
let me = this;
|
|
11
|
-
if (me.$$configured) {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
if (!config) {
|
|
15
|
-
config = new Config();
|
|
16
|
-
}
|
|
17
|
-
me.config = config;
|
|
18
|
-
|
|
19
|
-
if (!log) {
|
|
20
|
-
log = loog({
|
|
21
|
-
prefixStyle: 'ascii'
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
me.log = log;
|
|
25
|
-
me.$$configured = true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static recognize (dir) {
|
|
29
|
-
let me = this;
|
|
30
|
-
me.configure();
|
|
31
|
-
|
|
32
|
-
return new Promise((resolve, reject) => {
|
|
33
|
-
try {
|
|
34
|
-
let theDir = File.from(dir).canonicalize();
|
|
35
|
-
me.log.debug('Directory to recognize is: ' + theDir.canonicalPath());
|
|
36
|
-
let allProjects = me._getAllProjects();
|
|
37
|
-
let matching = allProjects.filter((p) => p.path.canonicalPath() === theDir.path);
|
|
38
|
-
if (matching.length > 0) {
|
|
39
|
-
me.log.debug(`Found ${matching.length} matching projects`);
|
|
40
|
-
let base = matching.filter((p) => !~p.name.indexOf('#'))[0];
|
|
41
|
-
me.log.debug('Base project is: ' + base.name);
|
|
42
|
-
|
|
43
|
-
base.matching = matching;
|
|
44
|
-
let gitDir = base.path.up('.git');
|
|
45
|
-
if (gitDir) {
|
|
46
|
-
git(gitDir.path).branchLocal((error, summary) => {
|
|
47
|
-
base.branch = summary.current;
|
|
48
|
-
me._getProjectEnvironment(base, resolve, reject);
|
|
49
|
-
});
|
|
50
|
-
} else {
|
|
51
|
-
me._getProjectEnvironment(base, resolve, reject);
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
resolve(new Environment());
|
|
55
|
-
}
|
|
56
|
-
} catch (ex) {
|
|
57
|
-
reject(ex);
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
static _getAllProjects (refresh) {
|
|
63
|
-
let me = this;
|
|
64
|
-
let allProjects = me.projects;
|
|
65
|
-
if (!allProjects || refresh) {
|
|
66
|
-
let defaults = me.config.get('project_defaults');
|
|
67
|
-
if (!defaults || !defaults.base) {
|
|
68
|
-
allProjects = [];
|
|
69
|
-
me.projects = allProjects;
|
|
70
|
-
return allProjects;
|
|
71
|
-
}
|
|
72
|
-
let baseDir = File.from(defaults.base);
|
|
73
|
-
let projectsMap = me.config.get('projects');
|
|
74
|
-
allProjects = [];
|
|
75
|
-
if (projectsMap) {
|
|
76
|
-
for (let name in projectsMap) {
|
|
77
|
-
let project = projectsMap[name];
|
|
78
|
-
project.name = name;
|
|
79
|
-
project.path = baseDir.join(project.path);
|
|
80
|
-
allProjects.push(project);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
me.projects = allProjects;
|
|
84
|
-
}
|
|
85
|
-
return allProjects;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
static _getProjectEnvironment(base, resolve, reject) {
|
|
89
|
-
let me = this;
|
|
90
|
-
let projectCfg = base;
|
|
91
|
-
let exactName = `${base.name}#${base.branch}`;
|
|
92
|
-
try {
|
|
93
|
-
let exactProj = me.projects.filter((p) => p.name === exactName)[0];
|
|
94
|
-
if (exactProj) {
|
|
95
|
-
projectCfg = exactProj;
|
|
96
|
-
}
|
|
97
|
-
projectCfg.exactName = exactName;
|
|
98
|
-
resolve(new ProjectEnvironment(projectCfg));
|
|
99
|
-
} catch (ex) {
|
|
100
|
-
reject(ex);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
module.exports = {
|
|
106
|
-
ProjectEnvironment,
|
|
107
|
-
EnvironmentRecognizer
|
|
108
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const Environment = require('./base');
|
|
2
|
-
const Project = require('../project');
|
|
3
|
-
|
|
4
|
-
class ProjectEnvironment extends Environment {
|
|
5
|
-
static load (project, defaults) {
|
|
6
|
-
let environment = new ProjectEnvironment(project, defaults);
|
|
7
|
-
return environment;
|
|
8
|
-
}
|
|
9
|
-
//------------------------------
|
|
10
|
-
constructor (config, defaults) {
|
|
11
|
-
if (config.$isProject) {
|
|
12
|
-
super({
|
|
13
|
-
project: config
|
|
14
|
-
});
|
|
15
|
-
} else {
|
|
16
|
-
super({
|
|
17
|
-
project: new Project(config.name, config, defaults)
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
ProjectEnvironment.$isProjectEnvironment = true;
|
|
24
|
-
ProjectEnvironment.prototype.$isProjectEnvironment = true;
|
|
25
|
-
|
|
26
|
-
module.exports = ProjectEnvironment;
|