@rune-cli/rune 0.0.4 → 0.0.6

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/dist/cli.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import { i as successResult, n as runManifestCommand, r as failureResult, t as writeCommandExecutionResult } from "./write-result-qylmqXvG.mjs";
2
+ import { a as isHelpFlag, i as successResult, n as runManifestCommand, o as isVersionFlag, r as failureResult, t as writeCommandExecutionResult } from "./write-result-DOrdlrbw.mjs";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { build } from "esbuild";
5
5
  import { cp, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
6
6
  import path from "node:path";
7
7
  import ts from "typescript";
8
8
  //#region package.json
9
- var version = "0.0.4";
9
+ var version = "0.0.6";
10
10
  //#endregion
11
11
  //#region src/manifest/generate-manifest.ts
12
12
  const COMMAND_ENTRY_FILE = "index.ts";
@@ -116,26 +116,31 @@ function resolveCommandsDirectory(projectRoot) {
116
116
  function resolveDistDirectory(projectRoot) {
117
117
  return path.join(projectRoot, DIST_DIRECTORY_NAME);
118
118
  }
119
- async function readProjectCliName(projectRoot) {
119
+ async function readProjectCliInfo(projectRoot) {
120
120
  const packageJsonPath = path.join(projectRoot, "package.json");
121
121
  try {
122
122
  const packageJsonContents = await readFile(packageJsonPath, "utf8");
123
123
  const packageJson = JSON.parse(packageJsonContents);
124
+ let name;
124
125
  if (packageJson.bin && typeof packageJson.bin === "object") {
125
126
  const binNames = Object.keys(packageJson.bin).sort((left, right) => left.localeCompare(right));
126
- if (binNames.length > 0) return binNames[0];
127
+ if (binNames.length > 0) name = binNames[0];
127
128
  }
128
- if (packageJson.name && packageJson.name.length > 0) return packageJson.name.split("/").at(-1) ?? packageJson.name;
129
+ if (!name && packageJson.name && packageJson.name.length > 0) name = packageJson.name.split("/").at(-1) ?? packageJson.name;
130
+ return {
131
+ name: name ?? path.basename(projectRoot),
132
+ version: packageJson.version
133
+ };
129
134
  } catch (error) {
130
135
  if (error.code !== "ENOENT") throw error;
131
136
  }
132
- return path.basename(projectRoot);
137
+ return { name: path.basename(projectRoot) };
133
138
  }
134
139
  async function assertCommandsDirectoryExists(commandsDirectory) {
135
140
  if (!(await stat(commandsDirectory).catch((error) => {
136
141
  if (error.code === "ENOENT") return;
137
142
  throw error;
138
- }))?.isDirectory()) throw new Error(`Commands directory not found: ${commandsDirectory}`);
143
+ }))?.isDirectory()) throw new Error(`Commands directory not found at ${COMMANDS_DIRECTORY_NAME}. Create it or check the --project <path> option.`);
139
144
  }
140
145
  //#endregion
141
146
  //#region src/cli/build-command.ts
@@ -200,13 +205,14 @@ async function copyBuiltAssets(sourceDirectory, distDirectory) {
200
205
  await cp(sourceEntryPath, distEntryPath);
201
206
  }));
202
207
  }
203
- function renderBuiltCliEntry(cliName, runtimeImportPath) {
208
+ function renderBuiltCliEntry(cliName, version, runtimeImportPath) {
204
209
  return `import { readFile } from "node:fs/promises";
205
210
  import { fileURLToPath } from "node:url";
206
211
 
207
212
  import { runManifestCommand, writeCommandExecutionResult } from ${JSON.stringify(runtimeImportPath)};
208
213
 
209
214
  const cliName = ${JSON.stringify(cliName)};
215
+ const version = ${JSON.stringify(version)};
210
216
  const distDirectoryUrl = new URL("./", import.meta.url);
211
217
  const manifestPath = fileURLToPath(new URL("./${BUILD_MANIFEST_FILENAME}", distDirectoryUrl));
212
218
  const manifestContents = await readFile(manifestPath, "utf8");
@@ -226,6 +232,7 @@ const result = await runManifestCommand({
226
232
  manifest: runtimeManifest,
227
233
  rawArgs: process.argv.slice(2),
228
234
  cliName,
235
+ version,
229
236
  cwd: process.cwd(),
230
237
  });
231
238
 
@@ -292,12 +299,12 @@ async function buildCommandEntries(projectRoot, sourceDirectory, distDirectory,
292
299
  write: true
293
300
  });
294
301
  }
295
- async function buildCliEntry(projectRoot, distDirectory, cliName) {
302
+ async function buildCliEntry(projectRoot, distDirectory, cliName, version) {
296
303
  const runtimeHelperEntryPath = await resolveRuntimeHelperEntryPath();
297
304
  await build({
298
305
  absWorkingDir: projectRoot,
299
306
  stdin: {
300
- contents: renderBuiltCliEntry(cliName, `./${path.basename(runtimeHelperEntryPath)}`),
307
+ contents: renderBuiltCliEntry(cliName, version, `./${path.basename(runtimeHelperEntryPath)}`),
301
308
  loader: "ts",
302
309
  resolveDir: path.dirname(runtimeHelperEntryPath),
303
310
  sourcefile: "rune-built-cli-entry.ts"
@@ -341,7 +348,7 @@ async function runBuildCommand(options) {
341
348
  await assertCommandsDirectoryExists(commandsDirectory);
342
349
  const sourceManifest = await generateCommandManifest({ commandsDirectory });
343
350
  const builtManifest = createBuiltManifest(sourceManifest, sourceDirectory);
344
- const cliName = await readProjectCliName(projectRoot);
351
+ const cliInfo = await readProjectCliInfo(projectRoot);
345
352
  await rm(distDirectory, {
346
353
  recursive: true,
347
354
  force: true
@@ -349,7 +356,7 @@ async function runBuildCommand(options) {
349
356
  await writeBuiltRuntimeFiles(distDirectory, builtManifest);
350
357
  await Promise.all([
351
358
  buildCommandEntries(projectRoot, sourceDirectory, distDirectory, sourceManifest),
352
- buildCliEntry(projectRoot, distDirectory, cliName),
359
+ buildCliEntry(projectRoot, distDirectory, cliInfo.name, cliInfo.version),
353
360
  copyBuiltAssets(sourceDirectory, distDirectory)
354
361
  ]);
355
362
  return successResult(`Built CLI to ${path.join(distDirectory, BUILD_CLI_FILENAME)}\n`);
@@ -386,6 +393,8 @@ Examples:
386
393
  async function runDevCommand(options) {
387
394
  try {
388
395
  const projectRoot = resolveProjectPath(options);
396
+ const cliInfo = await readProjectCliInfo(projectRoot);
397
+ if (cliInfo.version && options.rawArgs.length === 1 && isVersionFlag(options.rawArgs[0])) return successResult(`${cliInfo.name} v${cliInfo.version}\n`);
389
398
  const commandsDirectory = resolveCommandsDirectory(projectRoot);
390
399
  await assertCommandsDirectoryExists(commandsDirectory);
391
400
  const manifest = await generateCommandManifest({ commandsDirectory });
@@ -393,7 +402,8 @@ async function runDevCommand(options) {
393
402
  return runManifestCommand({
394
403
  manifest,
395
404
  rawArgs: options.rawArgs,
396
- cliName: await readProjectCliName(projectRoot),
405
+ cliName: cliInfo.name,
406
+ version: cliInfo.version,
397
407
  cwd: options.cwd
398
408
  });
399
409
  } catch (error) {
@@ -410,19 +420,13 @@ function tryParseProjectOption(argv, index) {
410
420
  };
411
421
  if (token === "--project") {
412
422
  const nextToken = argv[index + 1];
413
- if (!nextToken) return failureResult("Missing value for --project");
423
+ if (!nextToken) return failureResult("Missing value for --project. Usage: --project <path>");
414
424
  return {
415
425
  projectPath: nextToken,
416
426
  nextIndex: index + 2
417
427
  };
418
428
  }
419
429
  }
420
- function isHelpFlag(token) {
421
- return token === "--help" || token === "-h";
422
- }
423
- function isVersionFlag(token) {
424
- return token === "--version" || token === "-V";
425
- }
426
430
  function getRuneVersion() {
427
431
  return version;
428
432
  }
@@ -507,7 +511,7 @@ async function runRuneCli(options) {
507
511
  cwd: options.cwd
508
512
  });
509
513
  }
510
- return failureResult(`Unknown rune command: ${subcommand}`);
514
+ return failureResult(`Unknown command: ${subcommand}. Available commands: build, dev`);
511
515
  }
512
516
  //#endregion
513
517
  //#region src/cli.ts
@@ -30,6 +30,7 @@ interface RunManifestCommandOptions {
30
30
  readonly manifest: CommandManifest;
31
31
  readonly rawArgs: readonly string[];
32
32
  readonly cliName: string;
33
+ readonly version?: string | undefined;
33
34
  readonly cwd?: string | undefined;
34
35
  readonly loadCommand?: LoadCommandFn | undefined;
35
36
  }
package/dist/runtime.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as runManifestCommand, t as writeCommandExecutionResult } from "./write-result-qylmqXvG.mjs";
1
+ import { n as runManifestCommand, t as writeCommandExecutionResult } from "./write-result-DOrdlrbw.mjs";
2
2
  export { runManifestCommand, writeCommandExecutionResult };
@@ -1,5 +1,13 @@
1
1
  import { a as parseCommand, i as isSchemaField, n as executeCommand, r as formatFieldTypeHint } from "./dist-Bcn0FpHi.mjs";
2
2
  import { pathToFileURL } from "node:url";
3
+ //#region src/cli/flags.ts
4
+ function isHelpFlag(token) {
5
+ return token === "--help" || token === "-h";
6
+ }
7
+ function isVersionFlag(token) {
8
+ return token === "--version" || token === "-V";
9
+ }
10
+ //#endregion
3
11
  //#region src/cli/result.ts
4
12
  function successResult(stdout) {
5
13
  return {
@@ -60,7 +68,8 @@ async function formatUsageArguments(fields) {
60
68
  function getOptionUsageSuffix(fields) {
61
69
  return fields.length === 0 ? "" : "[options]";
62
70
  }
63
- function renderGroupHelp(manifest, node, cliName) {
71
+ function renderGroupHelp(options) {
72
+ const { manifest, node, cliName, version } = options;
64
73
  const nodeMap = createCommandManifestNodeMap(manifest);
65
74
  const entries = node.childNames.map((childName) => {
66
75
  return {
@@ -70,6 +79,14 @@ function renderGroupHelp(manifest, node, cliName) {
70
79
  });
71
80
  const parts = [`Usage: ${formatCommandName(cliName, node.pathSegments)} <command>`];
72
81
  if (entries.length > 0) parts.push(`Subcommands:\n${formatSectionEntries(entries)}`);
82
+ const optionEntries = [{
83
+ label: "-h, --help",
84
+ description: "Show help"
85
+ }, ...node.pathSegments.length === 0 && version ? [{
86
+ label: "-V, --version",
87
+ description: "Show the version number"
88
+ }] : []];
89
+ parts.push(`Options:\n${formatSectionEntries(optionEntries)}`);
73
90
  return `${parts.join("\n\n")}\n`;
74
91
  }
75
92
  async function renderCommandHelp(command, pathSegments, cliName) {
@@ -102,7 +119,12 @@ function renderUnknownCommandMessage(route, cliName) {
102
119
  }
103
120
  async function renderResolvedHelp(options) {
104
121
  if (options.route.kind === "unknown") return renderUnknownCommandMessage(options.route, options.cliName);
105
- if (options.route.kind === "group") return renderGroupHelp(options.manifest, options.route.node, options.cliName);
122
+ if (options.route.kind === "group") return renderGroupHelp({
123
+ manifest: options.manifest,
124
+ node: options.route.node,
125
+ cliName: options.cliName,
126
+ version: options.version
127
+ });
106
128
  return renderCommandHelp(await (options.loadCommand ?? defaultLoadCommand)(options.route.node), options.route.matchedPath, options.cliName);
107
129
  }
108
130
  //#endregion
@@ -126,7 +148,7 @@ function isOptionLikeToken(token) {
126
148
  return token === "--" || token.startsWith("-");
127
149
  }
128
150
  function getHelpRequested(args) {
129
- return args.includes("--help") || args.includes("-h");
151
+ return args.some(isHelpFlag);
130
152
  }
131
153
  function getSuggestionThreshold(candidate) {
132
154
  return Math.max(2, Math.floor(candidate.length / 3));
@@ -182,12 +204,14 @@ function resolveCommandPath(manifest, rawArgs) {
182
204
  //#endregion
183
205
  //#region src/manifest/run-manifest-command.ts
184
206
  async function runManifestCommand(options) {
207
+ if (options.version && options.rawArgs.length === 1 && isVersionFlag(options.rawArgs[0])) return successResult(`${options.cliName} v${options.version}\n`);
185
208
  const route = resolveCommandPath(options.manifest, options.rawArgs);
186
209
  if (route.kind === "unknown" || route.kind === "group" || route.helpRequested) {
187
210
  const output = await renderResolvedHelp({
188
211
  manifest: options.manifest,
189
212
  route,
190
213
  cliName: options.cliName,
214
+ version: options.version,
191
215
  loadCommand: options.loadCommand
192
216
  });
193
217
  return route.kind === "unknown" ? failureResult(output) : successResult(output);
@@ -222,4 +246,4 @@ async function writeCommandExecutionResult(result) {
222
246
  process.exitCode = result.exitCode;
223
247
  }
224
248
  //#endregion
225
- export { successResult as i, runManifestCommand as n, failureResult as r, writeCommandExecutionResult as t };
249
+ export { isHelpFlag as a, successResult as i, runManifestCommand as n, isVersionFlag as o, failureResult as r, writeCommandExecutionResult as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rune-cli/rune",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "Rune is a CLI framework built around the concept of file-based command routing.",
5
5
  "homepage": "https://github.com/morinokami/rune#readme",
6
6
  "bugs": {
@@ -43,7 +43,7 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/node": "24.12.0",
46
- "@typescript/native-preview": "7.0.0-dev.20260317.1",
46
+ "@typescript/native-preview": "7.0.0-dev.20260322.1",
47
47
  "typescript": "5.9.3",
48
48
  "vite-plus": "v0.1.13",
49
49
  "@rune-cli/core": "0.0.0"