gunshi 0.26.2 → 0.27.0-alpha.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 CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img width="196" src="./assets/logo.png">
2
+ <img alt="logo" width="196" src="./assets/logo.png">
3
3
  </p>
4
4
  <h1 align="center">🏯 Gunshi</h1>
5
5
 
@@ -102,6 +102,7 @@ About more details and usage, see [documentations](https://gunshi.dev)
102
102
  - [sourcemap-publisher](https://github.com/es-tooling/sourcemap-publisher): A tool to publish sourcemaps externally and rewrite sourcemap URLs at pre-publish time
103
103
  - [curxy](https://github.com/ryoppippi/curxy): An proxy worker for using ollama in cursor
104
104
  - [SiteMCP](https://github.com/ryoppippi/sitemcp): Fetch an entire site and use it as an MCP Server
105
+ - [ccusage](https://github.com/ryoppippi/ccusage): A CLI tool for analyzing Claude Code usage from local JSONL files.
105
106
 
106
107
  ## 🙌 Contributing guidelines
107
108
 
@@ -123,7 +124,7 @@ The development of Gunshi is supported by my OSS sponsors!
123
124
 
124
125
  <p align="center">
125
126
  <a href="https://cdn.jsdelivr.net/gh/kazupon/sponsors/sponsors.svg">
126
- <img src='https://cdn.jsdelivr.net/gh/kazupon/sponsors/sponsors.svg'/>
127
+ <img alt="sponsor" src='https://cdn.jsdelivr.net/gh/kazupon/sponsors/sponsors.svg'/>
127
128
  </a>
128
129
  </p>
129
130
 
package/lib/bone.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ import { ArgSchema, ArgToken, ArgValues, Args, Awaitable, CliOptions, Command, CommandCallMode, CommandContext, CommandContextCore, CommandContextExtension, CommandDecorator, CommandEnvironment, CommandExamplesFetcher, CommandLoader, CommandRunner, Commandable, DefaultGunshiParams, ExtendContext, ExtractArgs, ExtractExtensions, GunshiParams, GunshiParamsConstraint, LazyCommand, NormalizeToGunshiParams, RendererDecorator, ValidationErrorsDecorator } from "./types-ClnyW35e.js";
2
+
3
+ //#region src/cli/bone.d.ts
4
+
5
+ /**
6
+ * Run the command.
7
+ * @param args Command line arguments
8
+ * @param entry A {@link Command | entry command}, an {@link CommandRunner | inline command runner}, or a {@link LazyCommand | lazily-loaded command}
9
+ * @param options A {@link CliOptions | CLI options}
10
+ * @returns A rendered usage or undefined. if you will use {@link CliOptions.usageSilent} option, it will return rendered usage string.
11
+ */
12
+ declare function cli<A extends Args = Args, G extends GunshiParams = {
13
+ args: A;
14
+ extensions: {};
15
+ }>(argv: string[], entry: Command<G> | CommandRunner<G> | LazyCommand<G>, options?: CliOptions<G>): Promise<string | undefined>;
16
+ /**
17
+ * Run the command.
18
+ * @param args Command line arguments
19
+ * @param entry A {@link Command | entry command}, an {@link CommandRunner | inline command runner}, or a {@link LazyCommand | lazily-loaded command}
20
+ * @param options A {@link CliOptions | CLI options}
21
+ * @returns A rendered usage or undefined. if you will use {@link CliOptions.usageSilent} option, it will return rendered usage string.
22
+ */
23
+ declare function cli<E extends ExtendContext = ExtendContext, G extends GunshiParams = {
24
+ args: Args;
25
+ extensions: E;
26
+ }>(argv: string[], entry: Command<G> | CommandRunner<G> | LazyCommand<G>, options?: CliOptions<G>): Promise<string | undefined>;
27
+ /**
28
+ * Run the command.
29
+ * @param args Command line arguments
30
+ * @param entry A {@link Command | entry command}, an {@link CommandRunner | inline command runner}, or a {@link LazyCommand | lazily-loaded command}
31
+ * @param options A {@link CliOptions | CLI options}
32
+ * @returns A rendered usage or undefined. if you will use {@link CliOptions.usageSilent} option, it will return rendered usage string.
33
+ */
34
+ declare function cli<G extends GunshiParams = DefaultGunshiParams>(argv: string[], entry: Command<G> | CommandRunner<G> | LazyCommand<G>, options?: CliOptions<G>): Promise<string | undefined>;
35
+ //#endregion
36
+ export { ArgSchema, ArgToken, ArgValues, Args, Awaitable, CliOptions, Command, CommandCallMode, CommandContext, CommandContextCore, CommandContextExtension, CommandDecorator, CommandEnvironment, CommandExamplesFetcher, CommandLoader, CommandRunner, Commandable, DefaultGunshiParams, ExtendContext, ExtractArgs, ExtractExtensions, GunshiParams, GunshiParamsConstraint, LazyCommand, NormalizeToGunshiParams, RendererDecorator, ValidationErrorsDecorator, cli };
package/lib/bone.js ADDED
@@ -0,0 +1,18 @@
1
+ import "./context-DZ06drtF.js";
2
+ import "./utils-DPIUzHzX.js";
3
+ import { cliCore } from "./core-ClAxkDQL.js";
4
+
5
+ //#region src/cli/bone.ts
6
+ /**
7
+ * Run the command.
8
+ * @param args Command line arguments
9
+ * @param entry A {@link Command | entry command}, an {@link CommandRunner | inline command runner}, or a {@link LazyCommand | lazily-loaded command}
10
+ * @param options A {@link CliOptions | CLI options}
11
+ * @returns A rendered usage or undefined. if you will use {@link CliOptions.usageSilent} option, it will return rendered usage string.
12
+ */
13
+ async function cli(argv, entry, options = {}) {
14
+ return cliCore(argv, entry, options, []);
15
+ }
16
+
17
+ //#endregion
18
+ export { cli };
@@ -0,0 +1,107 @@
1
+ import { cliCore } from "./core-ClAxkDQL.js";
2
+ import { plugin } from "./core-6RK6f9Jg.js";
3
+ import { COMMON_ARGS, namespacedId, renderer } from "./src-Dgf8uyR8.js";
4
+
5
+ //#region ../plugin-global/src/types.ts
6
+ /**
7
+ * The unique identifier for the global options plugin.
8
+ */
9
+ const pluginId = namespacedId("global");
10
+
11
+ //#endregion
12
+ //#region ../plugin-global/src/decorator.ts
13
+ /**
14
+ * Decorator function to extend the command with global options.
15
+ */
16
+ const decorator = (baseRunner) => async (ctx) => {
17
+ const { values, validationError, extensions: { [pluginId]: { showVersion, showHeader, showUsage, showValidationErrors } } } = ctx;
18
+ if (values.version) return showVersion();
19
+ const buf = [];
20
+ const header = await showHeader();
21
+ if (header) buf.push(header);
22
+ if (values.help) {
23
+ const usage = await showUsage();
24
+ if (usage) {
25
+ buf.push(usage);
26
+ return buf.join("\n");
27
+ }
28
+ return;
29
+ }
30
+ if (validationError) return await showValidationErrors(validationError);
31
+ return baseRunner(ctx);
32
+ };
33
+ var decorator_default = decorator;
34
+
35
+ //#endregion
36
+ //#region ../plugin-global/src/extension.ts
37
+ function extension(ctx) {
38
+ return {
39
+ showVersion: () => {
40
+ const version = ctx.env.version || "unknown";
41
+ if (!ctx.env.usageSilent) ctx.log(version);
42
+ return version;
43
+ },
44
+ showHeader: async () => {
45
+ let header;
46
+ if (ctx.env.renderHeader != null) {
47
+ header = await ctx.env.renderHeader(ctx);
48
+ if (header) {
49
+ ctx.log(header);
50
+ ctx.log();
51
+ }
52
+ }
53
+ return header;
54
+ },
55
+ showUsage: async () => {
56
+ if (ctx.env.renderUsage != null) {
57
+ const usage = await ctx.env.renderUsage(ctx);
58
+ if (usage) {
59
+ ctx.log(usage);
60
+ return usage;
61
+ }
62
+ }
63
+ },
64
+ showValidationErrors: async (error) => {
65
+ if (ctx.env.renderValidationErrors === null) return;
66
+ if (ctx.env.renderValidationErrors !== void 0) {
67
+ const message = await ctx.env.renderValidationErrors(ctx, error);
68
+ ctx.log(message);
69
+ return message;
70
+ }
71
+ }
72
+ };
73
+ }
74
+
75
+ //#endregion
76
+ //#region ../plugin-global/src/index.ts
77
+ /**
78
+ * global options plugin
79
+ */
80
+ function global() {
81
+ return plugin({
82
+ id: pluginId,
83
+ name: "global options",
84
+ extension,
85
+ setup(ctx) {
86
+ for (const [name, schema] of Object.entries(COMMON_ARGS)) ctx.addGlobalOption(name, schema);
87
+ ctx.decorateCommand(decorator_default);
88
+ }
89
+ });
90
+ }
91
+
92
+ //#endregion
93
+ //#region src/cli/builtin.ts
94
+ /**
95
+ * Run the command.
96
+ * @param args Command line arguments
97
+ * @param entry A {@link Command | entry command}, an {@link CommandRunner | inline command runner}, or a {@link LazyCommand | lazily-loaded command}
98
+ * @param options A {@link CliOptions | CLI options}
99
+ * @returns A rendered usage or undefined. if you will use {@link CliOptions.usageSilent} option, it will return rendered usage string.
100
+ */
101
+ async function cli(argv, entry, options = {}) {
102
+ const builtInPlugins = [global(), renderer()];
103
+ return cliCore(argv, entry, options, builtInPlugins);
104
+ }
105
+
106
+ //#endregion
107
+ export { cli };
@@ -0,0 +1,87 @@
1
+ import { create, deepFreeze, isLazyCommand, log } from "./utils-DPIUzHzX.js";
2
+
3
+ //#region src/constants.ts
4
+ const ANONYMOUS_COMMAND_NAME = "(anonymous)";
5
+ const NOOP = () => {};
6
+ const COMMAND_OPTIONS_DEFAULT = {
7
+ name: void 0,
8
+ description: void 0,
9
+ version: void 0,
10
+ cwd: void 0,
11
+ usageSilent: false,
12
+ subCommands: void 0,
13
+ leftMargin: 2,
14
+ middleMargin: 10,
15
+ usageOptionType: false,
16
+ usageOptionValue: true,
17
+ renderHeader: void 0,
18
+ renderUsage: void 0,
19
+ renderValidationErrors: void 0,
20
+ plugins: void 0
21
+ };
22
+
23
+ //#endregion
24
+ //#region src/context.ts
25
+ /**
26
+ * Create a {@link CommandContext | command context}
27
+ * @param param A {@link CommandContextParams | parameters} to create a {@link CommandContext | command context}
28
+ * @returns A {@link CommandContext | command context}, which is readonly
29
+ */
30
+ async function createCommandContext({ args, values, positionals, rest, argv, tokens, command, extensions = {}, cliOptions, callMode = "entry", omitted = false, validationError }) {
31
+ /**
32
+ * normailize the options schema and values, to avoid prototype pollution
33
+ */
34
+ const _args = Object.entries(args).reduce((acc, [key, value]) => {
35
+ acc[key] = Object.assign(create(), value);
36
+ return acc;
37
+ }, create());
38
+ /**
39
+ * setup the environment
40
+ */
41
+ const env = Object.assign(create(), COMMAND_OPTIONS_DEFAULT, cliOptions);
42
+ /**
43
+ * create the command context
44
+ */
45
+ const core = Object.assign(create(), {
46
+ name: getCommandName(command),
47
+ description: command.description,
48
+ omitted,
49
+ callMode,
50
+ env,
51
+ args: _args,
52
+ values,
53
+ positionals,
54
+ rest,
55
+ _: argv,
56
+ tokens,
57
+ toKebab: command.toKebab,
58
+ log: cliOptions.usageSilent ? NOOP : log,
59
+ validationError
60
+ });
61
+ /**
62
+ * extend the command context with extensions
63
+ */
64
+ if (Object.keys(extensions).length > 0) {
65
+ const ext = create(null);
66
+ Object.defineProperty(core, "extensions", {
67
+ value: ext,
68
+ writable: false,
69
+ enumerable: true,
70
+ configurable: true
71
+ });
72
+ for (const [key, extension] of Object.entries(extensions)) {
73
+ ext[key] = await extension.factory(core, command);
74
+ if (extension.onFactory) await extension.onFactory(core, command);
75
+ }
76
+ }
77
+ const ctx = deepFreeze(core, ["extensions"]);
78
+ return ctx;
79
+ }
80
+ function getCommandName(cmd) {
81
+ if (isLazyCommand(cmd)) return cmd.commandName || cmd.name || ANONYMOUS_COMMAND_NAME;
82
+ else if (typeof cmd === "object") return cmd.name || ANONYMOUS_COMMAND_NAME;
83
+ else return ANONYMOUS_COMMAND_NAME;
84
+ }
85
+
86
+ //#endregion
87
+ export { ANONYMOUS_COMMAND_NAME, COMMAND_OPTIONS_DEFAULT, NOOP, createCommandContext };
package/lib/context.d.ts CHANGED
@@ -1,19 +1,22 @@
1
- import { CliOptions, Command, CommandCallMode, CommandContext, LazyCommand } from "./types-DtEE4hKC.js";
2
- import { ArgToken, ArgValues, Args } from "args-tokens";
1
+ import { ArgToken, ArgValues, CliOptions, Command, CommandCallMode, CommandContext, CommandContextExtension, DefaultGunshiParams, ExtendContext, ExtractArgs, GunshiParams, GunshiParamsConstraint, LazyCommand } from "./types-ClnyW35e.js";
3
2
 
4
3
  //#region src/context.d.ts
5
- /**
6
- * Parameters of {@link createCommandContext}
7
- */
8
4
 
5
+ /**
6
+ * Extract extension return types from extensions record
7
+ * @internal
8
+ */
9
+ type ExtractExtensions<E extends Record<string, CommandContextExtension>> = { [K in keyof E]: E[K] extends CommandContextExtension<infer T> ? T : never };
9
10
  /**
10
11
  * Parameters of {@link createCommandContext}
11
12
  */
12
- interface CommandContextParams<A extends Args, V> {
13
+ interface CommandContextParams<G extends GunshiParams | {
14
+ extensions: ExtendContext;
15
+ }, V extends ArgValues<ExtractArgs<G>>, C extends Command<G> | LazyCommand<G> = Command<G>, E extends Record<string, CommandContextExtension> = Record<string, CommandContextExtension>> {
13
16
  /**
14
17
  * An arguments of target command
15
18
  */
16
- args: A;
19
+ args: ExtractArgs<G>;
17
20
  /**
18
21
  * A values of target command
19
22
  */
@@ -45,18 +48,26 @@ interface CommandContextParams<A extends Args, V> {
45
48
  /**
46
49
  * A target command
47
50
  */
48
- command: Command<A> | LazyCommand<A>;
51
+ command: C;
52
+ /**
53
+ * Plugin extensions to apply as the command context extension.
54
+ */
55
+ extensions?: E;
49
56
  /**
50
57
  * A command options, which is spicialized from `cli` function
51
58
  */
52
- cliOptions: CliOptions<A>;
59
+ cliOptions: CliOptions<G>;
60
+ /**
61
+ * Validation error from argument parsing.
62
+ */
63
+ validationError?: AggregateError;
53
64
  }
54
65
  /**
55
66
  * Create a {@link CommandContext | command context}
56
67
  * @param param A {@link CommandContextParams | parameters} to create a {@link CommandContext | command context}
57
68
  * @returns A {@link CommandContext | command context}, which is readonly
58
69
  */
59
- declare function createCommandContext<A extends Args = Args, V extends ArgValues<A> = ArgValues<A>>({
70
+ declare function createCommandContext<G extends GunshiParamsConstraint = DefaultGunshiParams, V extends ArgValues<ExtractArgs<G>> = ArgValues<ExtractArgs<G>>, C extends Command<G> | LazyCommand<G> = Command<G>, E extends Record<string, CommandContextExtension> = {}>({
60
71
  args,
61
72
  values,
62
73
  positionals,
@@ -64,8 +75,14 @@ declare function createCommandContext<A extends Args = Args, V extends ArgValues
64
75
  argv,
65
76
  tokens,
66
77
  command,
78
+ extensions,
67
79
  cliOptions,
68
80
  callMode,
69
- omitted
70
- }: CommandContextParams<A, V>): Promise<Readonly<CommandContext<A, V>>>; //#endregion
71
- export { createCommandContext };
81
+ omitted,
82
+ validationError
83
+ }: CommandContextParams<G, V, C, E>): Promise<{} extends ExtractExtensions<E> ? Readonly<CommandContext<G>> : Readonly<CommandContext<GunshiParams<{
84
+ args: ExtractArgs<G>;
85
+ extensions: ExtractExtensions<E>;
86
+ }>>>>;
87
+ //#endregion
88
+ export { ExtractExtensions, createCommandContext };
package/lib/context.js CHANGED
@@ -1,4 +1,4 @@
1
- import "./utils-D41C8Abf.js";
2
- import { createCommandContext } from "./context-D_EmfRNA.js";
1
+ import { createCommandContext } from "./context-DZ06drtF.js";
2
+ import "./utils-DPIUzHzX.js";
3
3
 
4
4
  export { createCommandContext };
@@ -0,0 +1,46 @@
1
+ //#region src/plugin/core.ts
2
+ /**
3
+ * Define a plugin
4
+ * @param options - {@link PluginOptions | plugin options}
5
+ * @returns A defined plugin.
6
+ * @since v0.27.0
7
+ */
8
+ function plugin(options) {
9
+ const { id, name, setup, extension, onExtension, dependencies } = options;
10
+ const pluginFn = async (ctx) => {
11
+ if (setup) await setup(ctx);
12
+ };
13
+ return Object.defineProperties(pluginFn, {
14
+ id: {
15
+ value: id,
16
+ writable: false,
17
+ enumerable: true,
18
+ configurable: true
19
+ },
20
+ ...name && { name: {
21
+ value: name,
22
+ writable: false,
23
+ enumerable: true,
24
+ configurable: true
25
+ } },
26
+ ...dependencies && { dependencies: {
27
+ value: dependencies,
28
+ writable: false,
29
+ enumerable: true,
30
+ configurable: true
31
+ } },
32
+ ...extension && { extension: {
33
+ value: {
34
+ key: Symbol(id),
35
+ factory: extension,
36
+ onFactory: onExtension
37
+ },
38
+ writable: false,
39
+ enumerable: true,
40
+ configurable: true
41
+ } }
42
+ });
43
+ }
44
+
45
+ //#endregion
46
+ export { plugin };
@@ -0,0 +1,285 @@
1
+ import { ANONYMOUS_COMMAND_NAME, COMMAND_OPTIONS_DEFAULT, NOOP, createCommandContext } from "./context-DZ06drtF.js";
2
+ import { create, isLazyCommand, resolveLazyCommand } from "./utils-DPIUzHzX.js";
3
+ import { parseArgs, resolveArgs } from "args-tokens";
4
+
5
+ //#region src/decorators.ts
6
+ const EMPTY_RENDERER = async () => "";
7
+ /**
8
+ * Factory function for creating a decorators manager.
9
+ * @returns A new decorators manager instance
10
+ */
11
+ function createDecorators() {
12
+ /**
13
+ * private states
14
+ */
15
+ const headerDecorators = [];
16
+ const usageDecorators = [];
17
+ const validationDecorators = [];
18
+ const commandDecorators = [];
19
+ /**
20
+ * helper function for building renderers
21
+ */
22
+ function buildRenderer(decorators, defaultRenderer) {
23
+ if (decorators.length === 0) return defaultRenderer;
24
+ let renderer = defaultRenderer;
25
+ for (const decorator of decorators) {
26
+ const previousRenderer = renderer;
27
+ renderer = (ctx) => decorator(previousRenderer, ctx);
28
+ }
29
+ return renderer;
30
+ }
31
+ /**
32
+ * public interfaces
33
+ */
34
+ return Object.freeze({
35
+ addHeaderDecorator(decorator) {
36
+ headerDecorators.push(decorator);
37
+ },
38
+ addUsageDecorator(decorator) {
39
+ usageDecorators.push(decorator);
40
+ },
41
+ addValidationErrorsDecorator(decorator) {
42
+ validationDecorators.push(decorator);
43
+ },
44
+ addCommandDecorator(decorator) {
45
+ commandDecorators.push(decorator);
46
+ },
47
+ get commandDecorators() {
48
+ return [...commandDecorators];
49
+ },
50
+ getHeaderRenderer() {
51
+ return buildRenderer(headerDecorators, EMPTY_RENDERER);
52
+ },
53
+ getUsageRenderer() {
54
+ return buildRenderer(usageDecorators, EMPTY_RENDERER);
55
+ },
56
+ getValidationErrorsRenderer() {
57
+ if (validationDecorators.length === 0) return EMPTY_RENDERER;
58
+ let renderer = EMPTY_RENDERER;
59
+ for (const decorator of validationDecorators) {
60
+ const previousRenderer = renderer;
61
+ renderer = (ctx, error) => decorator(previousRenderer, ctx, error);
62
+ }
63
+ return renderer;
64
+ }
65
+ });
66
+ }
67
+
68
+ //#endregion
69
+ //#region src/plugin/context.ts
70
+ /**
71
+ * Factory function for creating a plugin context.
72
+ * @param decorators - A {@link Decorators} instance.
73
+ * @returns A new {@link PluginContext} instance.
74
+ */
75
+ function createPluginContext(decorators) {
76
+ /**
77
+ * private states
78
+ */
79
+ const globalOptions = new Map();
80
+ /**
81
+ * public interfaces
82
+ */
83
+ return Object.freeze({
84
+ get globalOptions() {
85
+ return new Map(globalOptions);
86
+ },
87
+ addGlobalOption(name, schema) {
88
+ if (!name) throw new Error("Option name must be a non-empty string");
89
+ if (globalOptions.has(name)) throw new Error(`Global option '${name}' is already registered`);
90
+ globalOptions.set(name, schema);
91
+ },
92
+ decorateHeaderRenderer(decorator) {
93
+ decorators.addHeaderDecorator(decorator);
94
+ },
95
+ decorateUsageRenderer(decorator) {
96
+ decorators.addUsageDecorator(decorator);
97
+ },
98
+ decorateValidationErrorsRenderer(decorator) {
99
+ decorators.addValidationErrorsDecorator(decorator);
100
+ },
101
+ decorateCommand(decorator) {
102
+ decorators.addCommandDecorator(decorator);
103
+ }
104
+ });
105
+ }
106
+
107
+ //#endregion
108
+ //#region src/plugin/dependency.ts
109
+ /**
110
+ * Resolve plugin dependencies using topological sort
111
+ * @param plugins - Array of plugins to resolve
112
+ * @returns Array of plugins sorted by dependencies
113
+ * @throws Error if circular dependency is detected or required dependency is missing
114
+ */
115
+ function resolveDependencies(plugins) {
116
+ const sorted = [];
117
+ const visited = new Set();
118
+ const visiting = new Set();
119
+ const pluginMap = new Map();
120
+ for (const plugin of plugins) if (plugin.id) {
121
+ if (pluginMap.has(plugin.id)) console.warn(`Duplicate plugin id detected: \`${plugin.id}\``);
122
+ pluginMap.set(plugin.id, plugin);
123
+ }
124
+ function visit(plugin) {
125
+ if (!plugin.id) return;
126
+ if (visited.has(plugin.id)) return;
127
+ if (visiting.has(plugin.id)) throw new Error(`Circular dependency detected: \`${[...visiting].join(` -> `) + " -> " + plugin.id}\``);
128
+ visiting.add(plugin.id);
129
+ const deps = plugin.dependencies || [];
130
+ for (const dep of deps) {
131
+ const depId = typeof dep === "string" ? dep : dep.id;
132
+ const isOptional = typeof dep === "string" ? false : dep.optional || false;
133
+ const depPlugin = pluginMap.get(depId);
134
+ if (!depPlugin && !isOptional) throw new Error(`Missing required dependency: \`${depId}\` on \`${plugin.id}\``);
135
+ if (depPlugin) visit(depPlugin);
136
+ }
137
+ visiting.delete(plugin.id);
138
+ visited.add(plugin.id);
139
+ sorted.push(plugin);
140
+ }
141
+ for (const plugin of plugins) visit(plugin);
142
+ return sorted;
143
+ }
144
+
145
+ //#endregion
146
+ //#region src/cli/core.ts
147
+ async function cliCore(argv, entry, options, plugins) {
148
+ const decorators = createDecorators();
149
+ const pluginContext = createPluginContext(decorators);
150
+ const resolvedPlugins = await applyPlugins(pluginContext, [...plugins, ...options.plugins || []]);
151
+ const cliOptions = normalizeCliOptions(options, entry, decorators);
152
+ const tokens = parseArgs(argv);
153
+ const subCommand = getSubCommand(tokens);
154
+ const { commandName: name, command, callMode } = await resolveCommand(subCommand, entry, cliOptions);
155
+ if (!command) throw new Error(`Command not found: ${name || ""}`);
156
+ const args = resolveArguments(pluginContext, getCommandArgs(command));
157
+ const { values, positionals, rest, error } = resolveArgs(args, tokens, {
158
+ shortGrouping: true,
159
+ toKebab: command.toKebab,
160
+ skipPositional: cliOptions.subCommands.size > 0 ? 0 : -1
161
+ });
162
+ const omitted = !subCommand;
163
+ const commandContext = await createCommandContext({
164
+ args,
165
+ values,
166
+ positionals,
167
+ rest,
168
+ argv,
169
+ tokens,
170
+ omitted,
171
+ callMode,
172
+ command,
173
+ extensions: getPluginExtensions(resolvedPlugins),
174
+ validationError: error,
175
+ cliOptions
176
+ });
177
+ return await executeCommand(command, commandContext, name || "", decorators.commandDecorators);
178
+ }
179
+ async function applyPlugins(pluginContext, plugins) {
180
+ const sortedPlugins = resolveDependencies(plugins);
181
+ try {
182
+ for (const plugin of sortedPlugins)
183
+ /**
184
+ * NOTE(kazupon):
185
+ * strictly `Args` are not required for plugin installation.
186
+ * because the strictly `Args` required by each plugin are unknown,
187
+ * and the plugin side can not know what the user will specify.
188
+ */
189
+ await plugin(pluginContext);
190
+ } catch (error) {
191
+ console.error("Error loading plugin:", error.message);
192
+ }
193
+ return sortedPlugins;
194
+ }
195
+ function getCommandArgs(cmd) {
196
+ if (isLazyCommand(cmd)) return cmd.args || create();
197
+ else if (typeof cmd === "object") return cmd.args || create();
198
+ else return create();
199
+ }
200
+ function resolveArguments(pluginContext, args) {
201
+ return Object.assign(create(), Object.fromEntries(pluginContext.globalOptions), args);
202
+ }
203
+ function normalizeCliOptions(options, entry, decorators) {
204
+ const subCommands = new Map(options.subCommands);
205
+ if (options.subCommands) {
206
+ if (isLazyCommand(entry)) subCommands.set(entry.commandName, entry);
207
+ else if (typeof entry === "object" && entry.name) subCommands.set(entry.name, entry);
208
+ }
209
+ const resolvedOptions = Object.assign(create(), COMMAND_OPTIONS_DEFAULT, options, { subCommands });
210
+ if (resolvedOptions.renderHeader === void 0) resolvedOptions.renderHeader = decorators.getHeaderRenderer();
211
+ if (resolvedOptions.renderUsage === void 0) resolvedOptions.renderUsage = decorators.getUsageRenderer();
212
+ if (resolvedOptions.renderValidationErrors === void 0) resolvedOptions.renderValidationErrors = decorators.getValidationErrorsRenderer();
213
+ return resolvedOptions;
214
+ }
215
+ function getSubCommand(tokens) {
216
+ const firstToken = tokens[0];
217
+ return firstToken && firstToken.kind === "positional" && firstToken.index === 0 && firstToken.value ? firstToken.value : "";
218
+ }
219
+ const CANNOT_RESOLVE_COMMAND = { callMode: "unexpected" };
220
+ async function resolveCommand(sub, entry, options) {
221
+ const omitted = !sub;
222
+ async function doResolveCommand() {
223
+ if (typeof entry === "function") if ("commandName" in entry && entry.commandName) return {
224
+ commandName: entry.commandName,
225
+ command: entry,
226
+ callMode: "entry"
227
+ };
228
+ else return {
229
+ command: { run: entry },
230
+ callMode: "entry"
231
+ };
232
+ else if (typeof entry === "object") return {
233
+ commandName: resolveEntryName(entry),
234
+ command: entry,
235
+ callMode: "entry"
236
+ };
237
+ else return CANNOT_RESOLVE_COMMAND;
238
+ }
239
+ if (omitted || options.subCommands?.size === 0) return doResolveCommand();
240
+ const cmd = options.subCommands?.get(sub);
241
+ if (cmd == null) return {
242
+ commandName: sub,
243
+ callMode: "unexpected"
244
+ };
245
+ if (isLazyCommand(cmd) && cmd.commandName == null) cmd.commandName = sub;
246
+ else if (typeof cmd === "object" && cmd.name == null) cmd.name = sub;
247
+ return {
248
+ commandName: sub,
249
+ command: cmd,
250
+ callMode: "subCommand"
251
+ };
252
+ }
253
+ function resolveEntryName(entry) {
254
+ return entry.name || ANONYMOUS_COMMAND_NAME;
255
+ }
256
+ function getPluginExtensions(plugins) {
257
+ const extensions = create();
258
+ for (const plugin of plugins) if (plugin.extension) {
259
+ const key = plugin.id;
260
+ if (extensions[key]) console.warn(`Plugin "${key}" is already installed. ignore it for command context extending.`);
261
+ else extensions[key] = plugin.extension;
262
+ }
263
+ return extensions;
264
+ }
265
+ async function executeCommand(cmd, ctx, name, decorators) {
266
+ const resolved = isLazyCommand(cmd) ? await resolveLazyCommand(cmd, name, true) : cmd;
267
+ const baseRunner = resolved.run || NOOP;
268
+ const decoratedRunner = decorators.reduceRight((runner, decorator) => decorator(runner), baseRunner);
269
+ try {
270
+ if (ctx.env.onBeforeCommand) await ctx.env.onBeforeCommand(ctx);
271
+ const result = await decoratedRunner(ctx);
272
+ if (ctx.env.onAfterCommand) await ctx.env.onAfterCommand(ctx, result);
273
+ return typeof result === "string" ? result : void 0;
274
+ } catch (error) {
275
+ if (ctx.env.onErrorCommand) try {
276
+ await ctx.env.onErrorCommand(ctx, error);
277
+ } catch (hookError) {
278
+ console.error("Error in onErrorCommand hook:", hookError);
279
+ }
280
+ throw error;
281
+ }
282
+ }
283
+
284
+ //#endregion
285
+ export { cliCore };