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.
Files changed (66) hide show
  1. package/README.md +19 -4
  2. package/bin/workon +1 -11
  3. package/dist/cli.js +2227 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/index.cjs +1216 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +280 -0
  8. package/dist/index.d.ts +280 -0
  9. package/dist/index.js +1173 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +68 -21
  12. package/.claude/settings.local.json +0 -11
  13. package/.cursorindexingignore +0 -3
  14. package/.history/.gitignore_20250806202718 +0 -30
  15. package/.history/.gitignore_20250806231444 +0 -32
  16. package/.history/.gitignore_20250806231450 +0 -32
  17. package/.history/lib/tmux_20250806233103.js +0 -109
  18. package/.history/lib/tmux_20250806233219.js +0 -109
  19. package/.history/lib/tmux_20250806233223.js +0 -109
  20. package/.history/lib/tmux_20250806233230.js +0 -109
  21. package/.history/lib/tmux_20250806233231.js +0 -109
  22. package/.history/lib/tmux_20250807120751.js +0 -190
  23. package/.history/lib/tmux_20250807120757.js +0 -190
  24. package/.history/lib/tmux_20250807120802.js +0 -190
  25. package/.history/lib/tmux_20250807120808.js +0 -190
  26. package/.history/package_20250807114243.json +0 -43
  27. package/.history/package_20250807114257.json +0 -43
  28. package/.history/package_20250807114404.json +0 -43
  29. package/.history/package_20250807114409.json +0 -43
  30. package/.history/package_20250807114510.json +0 -43
  31. package/.history/package_20250807114637.json +0 -43
  32. package/.vscode/launch.json +0 -20
  33. package/.vscode/terminals.json +0 -11
  34. package/CHANGELOG.md +0 -103
  35. package/CLAUDE.md +0 -100
  36. package/cli/base.js +0 -16
  37. package/cli/config/index.js +0 -19
  38. package/cli/config/list.js +0 -26
  39. package/cli/config/set.js +0 -19
  40. package/cli/config/unset.js +0 -26
  41. package/cli/index.js +0 -184
  42. package/cli/interactive.js +0 -290
  43. package/cli/manage.js +0 -413
  44. package/cli/open.js +0 -414
  45. package/commands/base.js +0 -105
  46. package/commands/core/cwd/index.js +0 -86
  47. package/commands/core/ide/index.js +0 -84
  48. package/commands/core/web/index.js +0 -109
  49. package/commands/extensions/claude/index.js +0 -211
  50. package/commands/extensions/docker/index.js +0 -167
  51. package/commands/extensions/npm/index.js +0 -208
  52. package/commands/registry.js +0 -196
  53. package/demo-colon-syntax.js +0 -57
  54. package/docs/adr/001-command-centric-architecture.md +0 -304
  55. package/docs/adr/002-positional-command-arguments.md +0 -402
  56. package/docs/ideas.md +0 -93
  57. package/lib/config.js +0 -51
  58. package/lib/environment/base.js +0 -12
  59. package/lib/environment/index.js +0 -108
  60. package/lib/environment/project.js +0 -26
  61. package/lib/project.js +0 -68
  62. package/lib/tmux.js +0 -221
  63. package/lib/validation.js +0 -120
  64. package/test-architecture.js +0 -145
  65. package/test-colon-syntax.js +0 -85
  66. package/test-registry.js +0 -57
package/cli/index.js DELETED
@@ -1,184 +0,0 @@
1
- const {container} = require('./base');
2
-
3
- const File = require('phylo');
4
-
5
- const Config = require('../lib/config');
6
- const {EnvironmentRecognizer} = require('../lib/environment');
7
-
8
- const config = require('./config');
9
- const interactive = require('./interactive');
10
- const open = require('./open');
11
- const manage = require('./manage');
12
-
13
- class workon extends container {
14
- constructor (log) {
15
- super();
16
- let me = this;
17
- me.log = log || require('loog')({
18
- prefixStyle: 'ascii'
19
- });
20
- }
21
-
22
- run () {
23
- let me = this;
24
- me.initialize();
25
- me.prepareCompletion();
26
- return super.run();
27
- }
28
-
29
- initialize () {
30
- let me = this;
31
- me.log.debug('Log system initialized');
32
- me.rootDir = File.from(__dirname).up('package.json');
33
- me.log.debug(`Using ${me.rootDir} as root directory`);
34
- me.config = new Config();
35
- me.log.debug('Configuration system initialized');
36
- me.log.debug("Loading package config, 'pkg' namespace");
37
- me.config.set('pkg', me.rootDir.join('package.json').load());
38
- EnvironmentRecognizer.configure(me.config, me.log);
39
- }
40
-
41
- prepareCompletion () {
42
- let me = this;
43
- let tree = {
44
- config: [
45
- 'list', 'set', 'reset'
46
- ]
47
- };
48
- let projects = me.config.get('projects');
49
- if (projects) {
50
- Object.keys(projects).forEach((id) => {
51
- tree[id] = null;
52
- });
53
- }
54
- me.completion = require('omelette')('workon').tree(tree);
55
- me.completion.init();
56
- }
57
-
58
- execute (params, args) {
59
- let me = this;
60
-
61
- if (params.debug) {
62
- me.log.setLogLevel('debug');
63
- }
64
-
65
- if (params.completion) {
66
- me.log.debug('Setting up command-line completion');
67
- me.completion.setupShellInitFile();
68
- return true;
69
- } else if (params.init) {
70
- me.log.debug('Generating shell integration function');
71
- me.outputShellInit();
72
- return true;
73
- } else {
74
- let prom = Promise.resolve();
75
- if (!me.environment) {
76
- prom = EnvironmentRecognizer.recognize(File.cwd())
77
- .then((environment) => {
78
- me.environment = environment;
79
- });
80
- }
81
- return prom.then(() => super.execute(params, args).catch((err) => me.maybeOpen(err, args)));
82
- }
83
- }
84
-
85
- outputShellInit () {
86
- let me = this;
87
-
88
- // Get list of available commands from switchit
89
- let cmdNames = me.constructor.getAspects().commands.filter((c) => !!c).map((c) => c.name);
90
-
91
- // Get list of available switches from switchit
92
- let switches = me.constructor.getAspects().switches || [];
93
- let switchFlags = [];
94
- switches.forEach(sw => {
95
- switchFlags.push('--' + sw.name);
96
- if (sw.char) {
97
- switchFlags.push('-' + sw.char);
98
- }
99
- });
100
-
101
- // Add built-in switchit flags (help and version are automatically added by switchit)
102
- let builtinFlags = ['--help', '-h', '--version', '-v', 'help'];
103
-
104
- // Combine all non-shell commands and flags, removing duplicates
105
- let nonShellCommands = [...new Set(cmdNames.concat(switchFlags).concat(builtinFlags))];
106
- let casePattern = nonShellCommands.join('|');
107
-
108
- // Generate shell function that wraps workon calls
109
- let shellFunction = `
110
- # workon shell integration
111
- workon() {
112
- # Commands and flags that should NOT use shell mode
113
- case "$1" in
114
- ${casePattern})
115
- command workon "$@"
116
- return $?
117
- ;;
118
- esac
119
-
120
- # If no arguments provided, run interactive mode directly
121
- if [[ $# -eq 0 ]]; then
122
- command workon "$@"
123
- return $?
124
- fi
125
-
126
- # Default behavior: use shell mode for project opening
127
- local output
128
- output=$(command workon --shell "$@" 2>&1)
129
- local exit_code=$?
130
-
131
- if [[ $exit_code -eq 0 && -n "$output" ]]; then
132
- # Execute shell commands if workon succeeded and output exists
133
- eval "$output"
134
- else
135
- # Show any error output
136
- [[ -n "$output" ]] && echo "$output" >&2
137
- return $exit_code
138
- fi
139
- }`;
140
- console.log(shellFunction);
141
- }
142
-
143
- maybeOpen (err, args) {
144
- let me = this;
145
- let cmdNames = me.constructor.getAspects().commands.filter((c) => !!c).map((c) => c.name);
146
- let firstCmd = args._args.filter((a) => !/^-/.test(a))[0];
147
- if (!~cmdNames.indexOf(firstCmd)) {
148
- // ex. "workon projectName"
149
- let openCmd = me.commands.lookup('open').create(me);
150
- // Copy shell parameter to the open command
151
- if (me.params.shell) {
152
- openCmd.params = openCmd.params || {};
153
- openCmd.params.shell = true;
154
- }
155
- return openCmd.run(args._args);
156
- } else {
157
- // ex. "workon config asdf"
158
- throw err;
159
- }
160
- }
161
- }
162
-
163
- workon.define({
164
- help: {
165
- '': 'Work on something great!',
166
- debug: 'Provide debug logging output',
167
- completion: 'Configure and generate shell tab completion',
168
- shell: 'Output shell commands instead of spawning processes',
169
- init: 'Generate shell integration function for seamless directory switching'
170
- },
171
- switches: '[d#debug:boolean=false] [completion:boolean=false] [shell:boolean=false] [init:boolean=false]',
172
- commands: {
173
- '': 'open',
174
- interactive: {
175
- type: interactive,
176
- private: true
177
- },
178
- open,
179
- config,
180
- manage
181
- }
182
- });
183
-
184
- module.exports = workon;
@@ -1,290 +0,0 @@
1
- const { command } = require('./base');
2
- const inquirer = require('inquirer');
3
- const File = require('phylo');
4
- const Prompt = require('inquirer/lib/prompts/input');
5
- const deepAssign = require('deep-assign');
6
-
7
- class interactive extends command {
8
- execute (params) {
9
- let me = this;
10
- me.log.debug();
11
- me.showLogo();
12
- me.log.log();
13
- let name;
14
- let fromUser = false;
15
- if (!params.identifier || params.identifier === 'undefined') {
16
- me.log.debug('Name was not provided, auto-detecting');
17
- if (me.root().project) {
18
- me.log.debug('Name derived form current project');
19
- name = me.root().project;
20
- } else {
21
- me.log.debug('Name derived from current working directory');
22
- name = File.cwd().name;
23
- }
24
- } else {
25
- name = params.identifier;
26
- fromUser = true;
27
- }
28
- return me.startInteractive(name, fromUser);
29
- }
30
-
31
- showLogo () {
32
- let me = this;
33
- let version = me.config.get('pkg').version;
34
-
35
- if (!this._hasShownLogo) {
36
- this.log.log(` 8\u001b[2m${' '.repeat(Math.max(15-version.length-1, 1))+'v'+version}\u001b[22m\nYb db dP .d8b. 8d8b 8.dP \u001b[92m.d8b. 8d8b.\u001b[0m\n YbdPYbdP 8' .8 8P 88b \u001b[92m8' .8 8P Y8\u001b[0m\n YP YP \`Y8P' 8 8 Yb \u001b[92m\`Y8P' 8 8\u001b[0m`);
37
- this._hasShownLogo = true;
38
- }
39
- }
40
-
41
- startInteractive (defaultName, fromUser, showMain = false) {
42
- let me = this;
43
- let environment = me.root().environment;
44
- me.log.debug(`Name '${defaultName}' was${fromUser ? '' : ' not'} provided by the user`);
45
- me.log.debug();
46
- return inquirer.prompt(me._getFirstQuestion(defaultName, fromUser, showMain)).then(function (answers) {
47
- let questions = [];
48
- let defaults = me.config.get('project_defaults');
49
- let projects = me.config.get('projects');
50
- switch (answers.action) {
51
- case 'exit':
52
- return true;
53
- case 'more':
54
- return me.startInteractive(defaultName, fromUser, true);
55
- case 'init-project':
56
- return inquirer.prompt([{
57
- message: 'What is the name of the project?',
58
- default: defaultName,
59
- name: 'name',
60
- validate: (value) => {
61
- if (value in projects) {
62
- return 'Project already exists.';
63
- }
64
- if (/\w+#\w+/.test(value)) {
65
- let projectName = value.substring(0,value.indexOf('#'));
66
- if (projectName in projects) {
67
- return true;
68
- } else {
69
- return `Project '${projectName}' does not exist. Please create it before starting a branch.`;
70
- }
71
- } else {
72
- return true;
73
- }
74
- },
75
- when: (answers) => {
76
- if (fromUser) {
77
- answers.name = defaultName;
78
- let prompt = new Prompt({
79
- type: 'input',
80
- name: 'name',
81
- message: `What is the name of the project?`,
82
- status: 'answered',
83
- default: answers.name
84
- });
85
- return me.log.log(prompt.getQuestion());
86
- } else {
87
- return true;
88
- }
89
- }
90
- },{
91
- message: 'What is the path to the project?',
92
- default: (answers) => {
93
- if (!/\w+#\w+/.test(answers.name)) {
94
- return File.from(defaults.base).join(answers.name).path
95
- }
96
- },
97
- when: (answers) => {
98
- if (/\w+#\w+/.test(answers.name)) {
99
- let projectName = answers.name.substring(0,answers.name.indexOf('#'));
100
- answers.path = File.from(defaults.base).join(projects[projectName].path).absolutePath();
101
- let prompt = new Prompt({
102
- type: 'input',
103
- message: `What is the path to the project?`,
104
- status: 'answered',
105
- default: answers.path
106
- });
107
- return me.log.log(prompt.getQuestion());
108
- } else {
109
- return true;
110
- }
111
- },
112
- name: 'path',
113
- filter: (answer) => {
114
- let answerFile = File.from(answer);
115
- let defaultBase = File.from(defaults.base);
116
- if (!answerFile.isAbsolute()) {
117
- answerFile = defaultBase.join(answerFile);
118
- }
119
- try {
120
- let canonical = answerFile.canonicalize();
121
- if (canonical) {
122
- answerFile = canonical;
123
- } else {
124
- answerFile = answerFile.absolutify();
125
- }
126
- } catch (e) {
127
- answerFile = answerFile.absolutify();
128
- }
129
- return answerFile.relativize(defaultBase.path).path;
130
- }
131
- },{
132
- message: 'What is the IDE?',
133
- type: 'list',
134
- name: 'ide',
135
- choices: [{
136
- name: 'Visual Studio Code',
137
- value: 'vscode'
138
- },{
139
- name: 'IntelliJ IDEA',
140
- value: 'idea'
141
- },{
142
- name: 'Atom',
143
- value: 'atom'
144
- }]
145
- },{
146
- message: 'Which events should take place when opening?',
147
- type: 'checkbox',
148
- name: 'events',
149
- choices: [{
150
- name: 'Change terminal cwd to project path',
151
- value: 'cwd'
152
- }, {
153
- name: 'Open project in IDE',
154
- value: 'ide'
155
- }],
156
- filter: (answer) => {
157
- return {
158
- cwd: answer.indexOf('cwd') > -1,
159
- ide: answer.indexOf('ide') > -1
160
- }
161
- }
162
- }]).then((answers) => {
163
- let projects = me.config.get('projects');
164
- projects[answers.name] = {};
165
- deepAssign(projects[answers.name], answers);
166
- delete projects[answers.name].name;
167
- me.config.set('projects', projects);
168
-
169
- me.log.info(`Your project has been initialized.`);
170
- me.log.info(`Use 'workon ${answers.name}' to start working!`);
171
-
172
- return true;
173
- });
174
- case 'init-branch':
175
- return inquirer.prompt([{
176
- message: 'What is the name of the branch?',
177
- name: 'branch',
178
- validate: (value) => {
179
- if (/\w+#\w+/.test(value)) {
180
- return 'Branch name can\'t contain the "#" sign';
181
- }
182
- if (`${defaultName}#${value}` in projects) {
183
- return 'Branch already exists.';
184
- }
185
- return true;
186
- }
187
- }]).then((answers) => {
188
- answers.name = `${defaultName}#${answers.branch}`
189
- let projects = me.config.get('projects');
190
- projects[answers.name] = {};
191
- deepAssign(projects[answers.name], answers, projects[defaultName]);
192
- delete projects[answers.name].name;
193
- me.config.set('projects', projects);
194
-
195
- me.log.info(`Your project has been initialized.`);
196
- me.log.info(`Use 'workon ${answers.name}' to start working!`);
197
-
198
- return true;
199
- });
200
- case 'switch-project':
201
- me.log.info('Switch to an existing project');
202
- break;
203
- case 'switch-branch':
204
- me.log.info('Switch to an existing branch');
205
- break;
206
- case 'manage-projects':
207
- me.log.info('Manage existing projects');
208
- break;
209
- case 'manage-branches':
210
- me.log.info('Manage existing branches');
211
- break;
212
- }
213
- });
214
- }
215
-
216
- _getFirstQuestion (defaultName, fromUser, showMain) {
217
- let me = this;
218
- let environment = me.root().environment;
219
- if (!showMain && environment.$isProjectEnvironment && !fromUser) {
220
- return {
221
- type: 'list',
222
- name: 'action',
223
- message: () => environment.project.name,
224
- choices: [{
225
- name: 'Start a branch',
226
- value: 'init-branch'
227
- },{
228
- name: 'Switch branch',
229
- value: 'switch-branch'
230
- },{
231
- name: 'Manage branches',
232
- value: 'manage-branches'
233
- },
234
- new inquirer.Separator(),
235
- {
236
- name: 'More...',
237
- value: 'more'
238
- },{
239
- name: 'Exit',
240
- value: 'exit'
241
- }]
242
- };
243
- } else {
244
- return {
245
- type: 'list',
246
- name: 'action',
247
- message: 'What do you want to do?',
248
- choices: [{
249
- name: 'Start a new project',
250
- value: 'init-project'
251
- },{
252
- name: 'Open an existing project',
253
- value: 'switch-project'
254
- },{
255
- name: 'Manage projects',
256
- value: 'manage-projects'
257
- },
258
- new inquirer.Separator(),{
259
- name: 'Exit',
260
- value: 'exit'
261
- }],
262
- default: fromUser ? defaultName : undefined,
263
- when: (answers) => {
264
- if (fromUser) {
265
- answers.name = 'init-project';
266
- let prompt = new Prompt({
267
- type: 'input',
268
- name: 'name',
269
- message: `What do you want to do?`,
270
- default: 'Start a new project'
271
- });
272
- return me.log.log(prompt.getQuestion());
273
- }
274
- return true;
275
- }
276
- };
277
- }
278
- }
279
- }
280
-
281
- interactive.define({
282
- parameters: {
283
- identifier: {
284
- type: 'string',
285
- value: ''
286
- }
287
- }
288
- });
289
-
290
- module.exports = interactive;