@vlandoss/starter 0.3.0 → 0.4.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 CHANGED
@@ -16,15 +16,36 @@ It will adds the `vland` to your global workspace
16
16
 
17
17
  ## Usage
18
18
 
19
- > [!NOTE]
20
- > The documentation is WIP
21
-
22
19
  Run the help command:
23
20
 
24
21
  ```sh
25
22
  vland help
26
23
  ```
27
24
 
25
+ ## Shell completion
26
+
27
+ `vland` ships a `completion` subcommand that prints a shell-specific script. Add it to your shell rc file:
28
+
29
+ ```sh
30
+ # zsh — ~/.zshrc
31
+ eval "$(vland completion zsh)"
32
+
33
+ # bash — ~/.bashrc
34
+ eval "$(vland completion bash)"
35
+
36
+ # fish — ~/.config/fish/config.fish
37
+ vland completion fish | source
38
+ ```
39
+
40
+ **Prerequisite:** the [`usage`](https://usage.jdx.dev) CLI must be on your `PATH` (it powers completion at runtime). Install via one of:
41
+
42
+ ```sh
43
+ mise use -g usage
44
+ brew install usage
45
+ ```
46
+
47
+ When you upgrade `@vlandoss/starter`, the next shell session will pick up new commands automatically — no need to re-run anything.
48
+
28
49
  ## Troubleshooting
29
50
 
30
51
  To enable debug mode, set the `DEBUG` environment variable to `vland:*` before running *any* command.
package/bin ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env bash
2
+ set -e
3
+
4
+ SOURCE="${BASH_SOURCE[0]}"
5
+ while [ -L "$SOURCE" ]; do
6
+ TARGET="$(readlink "$SOURCE")"
7
+ case "$TARGET" in
8
+ /*) SOURCE="$TARGET" ;;
9
+ *) SOURCE="$(dirname "$SOURCE")/$TARGET" ;;
10
+ esac
11
+ done
12
+ DIR="$(cd "$(dirname "$SOURCE")" && pwd)"
13
+
14
+ if [ "$1" = "completion" ]; then
15
+ case "$2" in
16
+ bash | zsh | fish)
17
+ kdl="$DIR/dist/cli.usage.kdl"
18
+ if [ ! -f "$kdl" ]; then
19
+ echo "vland completion: missing $kdl. Reinstall @vlandoss/starter or run \`pnpm build\`." >&2
20
+ exit 1
21
+ fi
22
+ if ! command -v usage >/dev/null 2>&1; then
23
+ echo "vland completion: 'usage' CLI not found in PATH." >&2
24
+ echo "Install via: mise use -g usage | brew install usage" >&2
25
+ exit 1
26
+ fi
27
+ exec usage generate completion "$2" vland --file "$kdl"
28
+ ;;
29
+ esac
30
+ # Unknown shell or `--help`: fall through to Node so Commander prints help/errors.
31
+ fi
32
+
33
+ # In the source repo (tsdown.config.ts present, NOT shipped in the npm tarball),
34
+ # always run from src/ so live edits show up. In a published install, use the
35
+ # bundled dist/run.mjs.
36
+ if [ -f "$DIR/tsdown.config.ts" ]; then
37
+ exec node "$DIR/src/run.ts" "$@"
38
+ else
39
+ exec node "$DIR/dist/run.mjs" "$@"
40
+ fi
@@ -0,0 +1,31 @@
1
+ // @generated by @usage-spec/commander from Commander.js metadata
2
+ name vland
3
+ bin vland
4
+ version "0.4.0"
5
+ usage "[options] [command]"
6
+ flag --usage help="print KDL spec for this CLI (https://kdl.dev)"
7
+ cmd completion help="print shell completion script 🐚 (usage)" {
8
+ long_help "Prints a shell completion script for vland. Add to your shell rc file:\n\n bash: eval \"$(vland completion bash)\"\n zsh: eval \"$(vland completion zsh)\"\n fish: vland completion fish | source"
9
+ arg <shell> help="target shell" {
10
+ choices bash zsh fish
11
+ }
12
+ }
13
+ cmd init help="init a new project 🚀" {
14
+ flag "-d --dest" help="destination path to create folder (default: cwd)" {
15
+ arg <DEST>
16
+ }
17
+ flag --no-git help="skip to create a git repository" negate=--git default=#true
18
+ flag "-f --force" help="override existing files"
19
+ arg "[template]" help="the template to use" required=#false {
20
+ choices basic monorepo
21
+ }
22
+ }
23
+ cmd add help="add config files to a project 📁" {
24
+ flag "-d --dest" help="destination path to create folder (default: cwd)" {
25
+ arg <DEST>
26
+ }
27
+ flag "-f --force" help="override existing files"
28
+ arg "[slug]…" help="the config slugs to pick" required=#false var=#true {
29
+ choices biome changeset husky mise tsconfig tsup
30
+ }
31
+ }
package/dist/run.mjs CHANGED
@@ -4,6 +4,7 @@ import { Argument, Command, Option, createCommand } from "commander";
4
4
  import fs from "node:fs";
5
5
  import { createLoggy } from "@vlandoss/loggy";
6
6
  import nodePlop from "node-plop";
7
+ import { generateToStdout } from "@usage-spec/commander";
7
8
  //#region src/services/config.ts
8
9
  var ConfigService = class {
9
10
  #baseDir;
@@ -114,6 +115,38 @@ function createAddCommand(ctx) {
114
115
  }).addHelpText("afterAll", "\nUnder the hood, this command uses Plop.js to generate the project.");
115
116
  }
116
117
  //#endregion
118
+ //#region src/program/ui.ts
119
+ const vlandColor = colorize("#a78bfa");
120
+ const TOOL_LABELS = { USAGE: colorize("#24C55E")("usage") };
121
+ function getBannerText(version) {
122
+ return `
123
+ ${vlandColor(`
124
+ ██╗ ██╗██╗ █████╗ ███╗ ██╗██████╗
125
+ ██║ ██║██║ ██╔══██╗████╗ ██║██╔══██╗
126
+ ██║ ██║██║ ███████║██╔██╗ ██║██║ ██║
127
+ ╚██╗ ██╔╝██║ ██╔══██║██║╚██╗██║██║ ██║
128
+ ╚████╔╝ ███████╗██║ ██║██║ ╚████║██████╔╝
129
+ ╚═══╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ${text.version(version)}
130
+ `.trim())}
131
+
132
+ 🦉 ${palette.italic(palette.muted("The CLI to init a new project in"))} ${text.vland}\n`.trimStart();
133
+ }
134
+ //#endregion
135
+ //#region src/program/commands/completion.ts
136
+ const SHELLS = [
137
+ "bash",
138
+ "zsh",
139
+ "fish"
140
+ ];
141
+ function createCompletionCommand() {
142
+ return createCommand("completion").summary(`print shell completion script 🐚 (${TOOL_LABELS.USAGE})`).description(`Prints a shell completion script for vland. Add to your shell rc file:
143
+
144
+ bash: eval "$(vland completion bash)"
145
+ zsh: eval "$(vland completion zsh)"
146
+ fish: vland completion fish | source`).addArgument(new Argument("<shell>", `target shell`).choices(SHELLS)).addHelpText("afterAll", `\nUnder the hood, this command uses ${TOOL_LABELS.USAGE} (https://usage.jdx.dev).
147
+ Make sure to have it installed and available in your PATH.`);
148
+ }
149
+ //#endregion
117
150
  //#region src/actions/init.ts
118
151
  const GENERATOR_ID = "init";
119
152
  var InitAction = class {
@@ -172,27 +205,19 @@ function createInitCommand(ctx) {
172
205
  }).addHelpText("afterAll", "\nUnder the hood, this command uses Plop.js to generate the project.");
173
206
  }
174
207
  //#endregion
175
- //#region src/program/ui.ts
176
- const vlandColor = colorize("#a78bfa");
177
- function getBannerText(version) {
178
- return `
179
- ${vlandColor(`
180
- ██╗ ██╗██╗ █████╗ ███╗ ██╗██████╗
181
- ██║ ██║██║ ██╔══██╗████╗ ██║██╔══██╗
182
- ██║ ██║██║ ███████║██╔██╗ ██║██║ ██║
183
- ╚██╗ ██╔╝██║ ██╔══██║██║╚██╗██║██║ ██║
184
- ╚████╔╝ ███████╗██║ ██║██║ ╚████║██████╔╝
185
- ╚═══╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═════╝ ${text.version(version)}
186
- `.trim())}
187
-
188
- 🦉 ${palette.italic(palette.muted("The CLI to init a new project in"))} ${text.vland}\n`.trimStart();
208
+ //#region src/program/commands/usage.ts
209
+ function addUsage(program) {
210
+ return program.addOption(new Option("--usage", "print KDL spec for this CLI (https://kdl.dev)")).on("option:usage", () => {
211
+ generateToStdout(program);
212
+ process.exit(0);
213
+ });
189
214
  }
190
215
  //#endregion
191
216
  //#region src/program/index.ts
192
217
  async function createProgram(options) {
193
218
  const ctx = await createContext(options.binDir);
194
219
  const version = getVersion(ctx.binPkg);
195
- return new Command("vland").version(version, "-v, --version").addHelpText("before", getBannerText(version)).addCommand(createInitCommand(ctx)).addCommand(createAddCommand(ctx));
220
+ return addUsage(new Command("vland").version(version, "-v, --version").addHelpText("before", getBannerText(version)).addCommand(createCompletionCommand()).addCommand(createInitCommand(ctx)).addCommand(createAddCommand(ctx)));
196
221
  }
197
222
  //#endregion
198
223
  //#region src/run.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vlandoss/starter",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "The CLI to init a new project in Variable Land",
5
5
  "homepage": "https://github.com/variableland/dx/tree/main/packages/starter#readme",
6
6
  "bugs": {
@@ -19,10 +19,10 @@
19
19
  },
20
20
  "module": "src/main.ts",
21
21
  "bin": {
22
- "vland": "./bin.mjs"
22
+ "vland": "./bin"
23
23
  },
24
24
  "files": [
25
- "bin.mjs",
25
+ "bin",
26
26
  "dist",
27
27
  "src",
28
28
  "!src/**/__tests__",
@@ -31,6 +31,7 @@
31
31
  "tsconfig.json"
32
32
  ],
33
33
  "dependencies": {
34
+ "@usage-spec/commander": "1.1.0",
34
35
  "commander": "14.0.3",
35
36
  "node-plop": "0.32.3",
36
37
  "@vlandoss/clibuddy": "0.4.0",
@@ -46,7 +47,8 @@
46
47
  "@vlandoss/tsdown-config": "^0.0.1"
47
48
  },
48
49
  "scripts": {
49
- "build": "tsdown",
50
+ "build": "tsdown && pnpm build:kdl",
51
+ "build:kdl": "./bin --usage > dist/cli.usage.kdl",
50
52
  "test:types": "rr tsc"
51
53
  }
52
54
  }
@@ -0,0 +1,26 @@
1
+ import { Argument, createCommand } from "commander";
2
+ import { TOOL_LABELS } from "../ui.ts";
3
+
4
+ const SHELLS = ["bash", "zsh", "fish"] as const;
5
+
6
+ // Ghost command: registered with Commander purely for discoverability — it surfaces
7
+ // in `vland --help` and is baked into dist/cli.usage.kdl so the completion itself can
8
+ // suggest "completion" after `vland <TAB>`. The actual handler lives in the bash bin
9
+ // dispatcher, which intercepts `vland completion <shell>` before reaching Node.
10
+ export function createCompletionCommand() {
11
+ return createCommand("completion")
12
+ .summary(`print shell completion script 🐚 (${TOOL_LABELS.USAGE})`)
13
+ .description(
14
+ `Prints a shell completion script for vland. Add to your shell rc file:
15
+
16
+ bash: eval "$(vland completion bash)"
17
+ zsh: eval "$(vland completion zsh)"
18
+ fish: vland completion fish | source`,
19
+ )
20
+ .addArgument(new Argument("<shell>", `target shell`).choices(SHELLS))
21
+ .addHelpText(
22
+ "afterAll",
23
+ `\nUnder the hood, this command uses ${TOOL_LABELS.USAGE} (https://usage.jdx.dev).
24
+ Make sure to have it installed and available in your PATH.`,
25
+ );
26
+ }
@@ -0,0 +1,9 @@
1
+ import { generateToStdout } from "@usage-spec/commander";
2
+ import { type Command, Option } from "commander";
3
+
4
+ export function addUsage(program: Command) {
5
+ return program.addOption(new Option("--usage", "print KDL spec for this CLI (https://kdl.dev)")).on("option:usage", () => {
6
+ generateToStdout(program);
7
+ process.exit(0);
8
+ });
9
+ }
@@ -2,7 +2,9 @@ import { getVersion } from "@vlandoss/clibuddy";
2
2
  import { Command } from "commander";
3
3
  import { createContext } from "#src/services/ctx.ts";
4
4
  import { createAddCommand } from "./commands/add.ts";
5
+ import { createCompletionCommand } from "./commands/completion.ts";
5
6
  import { createInitCommand } from "./commands/init.ts";
7
+ import { addUsage } from "./commands/usage.ts";
6
8
  import { getBannerText } from "./ui.ts";
7
9
 
8
10
  export type Options = {
@@ -13,9 +15,12 @@ export async function createProgram(options: Options) {
13
15
  const ctx = await createContext(options.binDir);
14
16
  const version = getVersion(ctx.binPkg);
15
17
 
16
- return new Command("vland")
17
- .version(version, "-v, --version")
18
- .addHelpText("before", getBannerText(version))
19
- .addCommand(createInitCommand(ctx))
20
- .addCommand(createAddCommand(ctx));
18
+ return addUsage(
19
+ new Command("vland")
20
+ .version(version, "-v, --version")
21
+ .addHelpText("before", getBannerText(version))
22
+ .addCommand(createCompletionCommand())
23
+ .addCommand(createInitCommand(ctx))
24
+ .addCommand(createAddCommand(ctx)),
25
+ );
21
26
  }
package/src/program/ui.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import { colorize, palette, text } from "@vlandoss/clibuddy";
2
2
 
3
3
  const vlandColor = colorize("#a78bfa");
4
+ const usageColor = colorize("#24C55E");
5
+
6
+ export const TOOL_LABELS = {
7
+ USAGE: usageColor("usage"),
8
+ };
4
9
 
5
10
  // npx figlet -f "ANSI Shadow" "vland"
6
11
  export function getBannerText(version: string) {
package/bin.mjs DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- import "./dist/run.mjs";