bet-cli 0.1.0 → 0.1.2
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 +11 -1
- package/dist/commands/completion.js +108 -0
- package/dist/index.js +2 -0
- package/dist/lib/completion.js +16 -0
- package/package.json +1 -1
- package/src/commands/completion.ts +125 -0
- package/src/index.ts +3 -1
- package/src/lib/completion.ts +16 -0
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Requires **Node >= 20**.
|
|
|
31
31
|
If/when this is published to npm, it’s intended to be installable as:
|
|
32
32
|
|
|
33
33
|
```sh
|
|
34
|
-
npm install -g bet
|
|
34
|
+
npm install -g bet-cli
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
## Quick start
|
|
@@ -77,6 +77,15 @@ After that:
|
|
|
77
77
|
- `bet go <slug>` will `cd` your current shell into the project
|
|
78
78
|
- `bet list` / `bet search` can also “select and jump” in interactive mode
|
|
79
79
|
|
|
80
|
+
**Project name autocompletion:** To complete project names (slugs) when using `bet go`, `bet path`, or `bet info`, add to your rc file:
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
eval "$(bet completion zsh)" # zsh
|
|
84
|
+
eval "$(bet completion bash)" # bash
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Then Tab-complete the slug argument after `bet go `, `bet path `, or `bet info `.
|
|
88
|
+
|
|
80
89
|
## Core commands
|
|
81
90
|
|
|
82
91
|
- **`bet update`**: Scan configured roots and rebuild the project index.
|
|
@@ -94,6 +103,7 @@ After that:
|
|
|
94
103
|
- **`--print`**: print selected path only (no shell `cd`)
|
|
95
104
|
- **`--no-enter`**: do not run the project’s `onEnter` hook (if configured)
|
|
96
105
|
- **`bet shell`**: Print the shell integration snippet (see above).
|
|
106
|
+
- **`bet completion [bash|zsh]`**: Print shell completion script for project name autocompletion (see above).
|
|
97
107
|
|
|
98
108
|
## Config & data files
|
|
99
109
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getProjectSlugs } from "../lib/completion.js";
|
|
2
|
+
const SLUG_COMMANDS = ["go", "path", "info"];
|
|
3
|
+
const SUBCOMMANDS = [
|
|
4
|
+
"update",
|
|
5
|
+
"list",
|
|
6
|
+
"search",
|
|
7
|
+
"info",
|
|
8
|
+
"go",
|
|
9
|
+
"path",
|
|
10
|
+
"shell",
|
|
11
|
+
"completion",
|
|
12
|
+
];
|
|
13
|
+
function zshScript() {
|
|
14
|
+
const slugCommandsPattern = SLUG_COMMANDS.join("|");
|
|
15
|
+
return `#compdef bet
|
|
16
|
+
_bet() {
|
|
17
|
+
local -a subcommands
|
|
18
|
+
subcommands=(
|
|
19
|
+
'update:Scan roots and rebuild project index'
|
|
20
|
+
'list:List projects'
|
|
21
|
+
'search:Fuzzy-search projects'
|
|
22
|
+
'info:Show project details'
|
|
23
|
+
'go:Jump to a project'
|
|
24
|
+
'path:Print project path'
|
|
25
|
+
'shell:Print shell integration'
|
|
26
|
+
'completion:Print shell completion script'
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
if (( CURRENT == 2 )); then
|
|
30
|
+
_describe 'bet commands' subcommands
|
|
31
|
+
return
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
if [[ "${slugCommandsPattern}" == *"\$words[2]"* ]]; then
|
|
35
|
+
if (( CURRENT == 3 )); then
|
|
36
|
+
local -a slugs
|
|
37
|
+
slugs=(\$(command bet completion --list 2>/dev/null))
|
|
38
|
+
_describe 'project' slugs
|
|
39
|
+
fi
|
|
40
|
+
return
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
_default
|
|
44
|
+
}
|
|
45
|
+
compdef _bet bet
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
function bashScript() {
|
|
49
|
+
const subcommandsList = SUBCOMMANDS.join(" ");
|
|
50
|
+
const cw = "COMP_WORDS";
|
|
51
|
+
const cc = "COMP_CWORD";
|
|
52
|
+
const dollar = "$";
|
|
53
|
+
return `_bet_completions() {
|
|
54
|
+
local cur="${dollar}{${cw}[${cc}]}"
|
|
55
|
+
|
|
56
|
+
if (( ${cc} == 1 )); then
|
|
57
|
+
COMPREPLY=(\$(compgen -W "${subcommandsList}" -- "${dollar}cur"))
|
|
58
|
+
return
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
local cmd="${dollar}{${cw}[1]}"
|
|
62
|
+
if [[ "${dollar}cmd" == "go" || "${dollar}cmd" == "path" || "${dollar}cmd" == "info" ]]; then
|
|
63
|
+
if (( ${cc} == 2 )); then
|
|
64
|
+
local slugs
|
|
65
|
+
slugs=\$(command bet completion --list 2>/dev/null)
|
|
66
|
+
COMPREPLY=(\$(compgen -W "${dollar}slugs" -- "${dollar}cur"))
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
complete -F _bet_completions bet
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
export function registerCompletion(program) {
|
|
74
|
+
program
|
|
75
|
+
.command("completion [shell]")
|
|
76
|
+
.description("Print shell completion script for project name autocompletion")
|
|
77
|
+
.option("--list", "Print project slugs only (for use by completion script)")
|
|
78
|
+
.option("--prefix <prefix>", "Filter slugs by prefix")
|
|
79
|
+
.action(async (shell, options) => {
|
|
80
|
+
if (options.list) {
|
|
81
|
+
let slugs = await getProjectSlugs();
|
|
82
|
+
if (options.prefix?.length) {
|
|
83
|
+
const p = options.prefix.toLowerCase();
|
|
84
|
+
slugs = slugs.filter((s) => s.toLowerCase().startsWith(p));
|
|
85
|
+
}
|
|
86
|
+
for (const slug of slugs) {
|
|
87
|
+
process.stdout.write(`${slug}\n`);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const sh = shell?.toLowerCase() ?? "";
|
|
92
|
+
if (sh === "zsh") {
|
|
93
|
+
process.stdout.write(zshScript());
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (sh === "bash") {
|
|
97
|
+
process.stdout.write(bashScript());
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (shell !== undefined) {
|
|
101
|
+
process.stderr.write(`Unknown shell "${shell}". Use bash or zsh.\n`);
|
|
102
|
+
process.exitCode = 1;
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
process.stderr.write("Usage: bet completion [bash|zsh]\n eval \"$(bet completion zsh)\"\n");
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
});
|
|
108
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { registerInfo } from "./commands/info.js";
|
|
|
7
7
|
import { registerGo } from "./commands/go.js";
|
|
8
8
|
import { registerPath } from "./commands/path.js";
|
|
9
9
|
import { registerShell } from "./commands/shell.js";
|
|
10
|
+
import { registerCompletion } from "./commands/completion.js";
|
|
10
11
|
const program = new Command();
|
|
11
12
|
program
|
|
12
13
|
.name("bet")
|
|
@@ -19,4 +20,5 @@ registerInfo(program);
|
|
|
19
20
|
registerGo(program);
|
|
20
21
|
registerPath(program);
|
|
21
22
|
registerShell(program);
|
|
23
|
+
registerCompletion(program);
|
|
22
24
|
program.parseAsync(process.argv);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readConfig } from "./config.js";
|
|
2
|
+
import { listProjects } from "./projects.js";
|
|
3
|
+
/**
|
|
4
|
+
* Returns project slugs for shell completion. On missing config or error,
|
|
5
|
+
* returns an empty array so the completion path can exit 0 with no output.
|
|
6
|
+
*/
|
|
7
|
+
export async function getProjectSlugs() {
|
|
8
|
+
try {
|
|
9
|
+
const config = await readConfig();
|
|
10
|
+
const projects = listProjects(config);
|
|
11
|
+
return projects.map((p) => p.slug);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bet-cli",
|
|
3
3
|
"description": "Explore and jump between local projects.",
|
|
4
|
+
"version": "0.1.2",
|
|
4
5
|
"author": "Chris Mckenzie",
|
|
5
6
|
"license": "Apache-2.0",
|
|
6
7
|
"repository": {
|
|
@@ -14,7 +15,6 @@
|
|
|
14
15
|
"management",
|
|
15
16
|
"navigation"
|
|
16
17
|
],
|
|
17
|
-
"version": "0.1.0",
|
|
18
18
|
"type": "module",
|
|
19
19
|
"bin": {
|
|
20
20
|
"bet": "dist/index.js"
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { getProjectSlugs } from "../lib/completion.js";
|
|
3
|
+
|
|
4
|
+
const SLUG_COMMANDS = ["go", "path", "info"];
|
|
5
|
+
const SUBCOMMANDS = [
|
|
6
|
+
"update",
|
|
7
|
+
"list",
|
|
8
|
+
"search",
|
|
9
|
+
"info",
|
|
10
|
+
"go",
|
|
11
|
+
"path",
|
|
12
|
+
"shell",
|
|
13
|
+
"completion",
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
function zshScript(): string {
|
|
17
|
+
const slugCommandsPattern = SLUG_COMMANDS.join("|");
|
|
18
|
+
return `#compdef bet
|
|
19
|
+
_bet() {
|
|
20
|
+
local -a subcommands
|
|
21
|
+
subcommands=(
|
|
22
|
+
'update:Scan roots and rebuild project index'
|
|
23
|
+
'list:List projects'
|
|
24
|
+
'search:Fuzzy-search projects'
|
|
25
|
+
'info:Show project details'
|
|
26
|
+
'go:Jump to a project'
|
|
27
|
+
'path:Print project path'
|
|
28
|
+
'shell:Print shell integration'
|
|
29
|
+
'completion:Print shell completion script'
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
if (( CURRENT == 2 )); then
|
|
33
|
+
_describe 'bet commands' subcommands
|
|
34
|
+
return
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [[ "${slugCommandsPattern}" == *"\$words[2]"* ]]; then
|
|
38
|
+
if (( CURRENT == 3 )); then
|
|
39
|
+
local -a slugs
|
|
40
|
+
slugs=(\$(command bet completion --list 2>/dev/null))
|
|
41
|
+
_describe 'project' slugs
|
|
42
|
+
fi
|
|
43
|
+
return
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
_default
|
|
47
|
+
}
|
|
48
|
+
compdef _bet bet
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function bashScript(): string {
|
|
53
|
+
const subcommandsList = SUBCOMMANDS.join(" ");
|
|
54
|
+
const cw = "COMP_WORDS";
|
|
55
|
+
const cc = "COMP_CWORD";
|
|
56
|
+
const dollar = "$";
|
|
57
|
+
return `_bet_completions() {
|
|
58
|
+
local cur="${dollar}{${cw}[${cc}]}"
|
|
59
|
+
|
|
60
|
+
if (( ${cc} == 1 )); then
|
|
61
|
+
COMPREPLY=(\$(compgen -W "${subcommandsList}" -- "${dollar}cur"))
|
|
62
|
+
return
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
local cmd="${dollar}{${cw}[1]}"
|
|
66
|
+
if [[ "${dollar}cmd" == "go" || "${dollar}cmd" == "path" || "${dollar}cmd" == "info" ]]; then
|
|
67
|
+
if (( ${cc} == 2 )); then
|
|
68
|
+
local slugs
|
|
69
|
+
slugs=\$(command bet completion --list 2>/dev/null)
|
|
70
|
+
COMPREPLY=(\$(compgen -W "${dollar}slugs" -- "${dollar}cur"))
|
|
71
|
+
fi
|
|
72
|
+
fi
|
|
73
|
+
}
|
|
74
|
+
complete -F _bet_completions bet
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function registerCompletion(program: Command): void {
|
|
79
|
+
program
|
|
80
|
+
.command("completion [shell]")
|
|
81
|
+
.description("Print shell completion script for project name autocompletion")
|
|
82
|
+
.option("--list", "Print project slugs only (for use by completion script)")
|
|
83
|
+
.option("--prefix <prefix>", "Filter slugs by prefix")
|
|
84
|
+
.action(
|
|
85
|
+
async (
|
|
86
|
+
shell: string | undefined,
|
|
87
|
+
options: { list?: boolean; prefix?: string },
|
|
88
|
+
) => {
|
|
89
|
+
if (options.list) {
|
|
90
|
+
let slugs = await getProjectSlugs();
|
|
91
|
+
if (options.prefix?.length) {
|
|
92
|
+
const p = options.prefix.toLowerCase();
|
|
93
|
+
slugs = slugs.filter((s) => s.toLowerCase().startsWith(p));
|
|
94
|
+
}
|
|
95
|
+
for (const slug of slugs) {
|
|
96
|
+
process.stdout.write(`${slug}\n`);
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const sh = shell?.toLowerCase() ?? "";
|
|
102
|
+
if (sh === "zsh") {
|
|
103
|
+
process.stdout.write(zshScript());
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (sh === "bash") {
|
|
107
|
+
process.stdout.write(bashScript());
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (shell !== undefined) {
|
|
112
|
+
process.stderr.write(
|
|
113
|
+
`Unknown shell "${shell}". Use bash or zsh.\n`,
|
|
114
|
+
);
|
|
115
|
+
process.exitCode = 1;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
process.stderr.write(
|
|
120
|
+
"Usage: bet completion [bash|zsh]\n eval \"$(bet completion zsh)\"\n",
|
|
121
|
+
);
|
|
122
|
+
process.exitCode = 1;
|
|
123
|
+
},
|
|
124
|
+
);
|
|
125
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -7,13 +7,14 @@ import { registerInfo } from "./commands/info.js";
|
|
|
7
7
|
import { registerGo } from "./commands/go.js";
|
|
8
8
|
import { registerPath } from "./commands/path.js";
|
|
9
9
|
import { registerShell } from "./commands/shell.js";
|
|
10
|
+
import { registerCompletion } from "./commands/completion.js";
|
|
10
11
|
|
|
11
12
|
const program = new Command();
|
|
12
13
|
|
|
13
14
|
program
|
|
14
15
|
.name("bet")
|
|
15
16
|
.description("Explore and jump between local projects.")
|
|
16
|
-
.version("0.1.
|
|
17
|
+
.version("0.1.2");
|
|
17
18
|
|
|
18
19
|
registerUpdate(program);
|
|
19
20
|
registerList(program);
|
|
@@ -22,5 +23,6 @@ registerInfo(program);
|
|
|
22
23
|
registerGo(program);
|
|
23
24
|
registerPath(program);
|
|
24
25
|
registerShell(program);
|
|
26
|
+
registerCompletion(program);
|
|
25
27
|
|
|
26
28
|
program.parseAsync(process.argv);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readConfig } from "./config.js";
|
|
2
|
+
import { listProjects } from "./projects.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Returns project slugs for shell completion. On missing config or error,
|
|
6
|
+
* returns an empty array so the completion path can exit 0 with no output.
|
|
7
|
+
*/
|
|
8
|
+
export async function getProjectSlugs(): Promise<string[]> {
|
|
9
|
+
try {
|
|
10
|
+
const config = await readConfig();
|
|
11
|
+
const projects = listProjects(config);
|
|
12
|
+
return projects.map((p) => p.slug);
|
|
13
|
+
} catch {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
}
|