@forinda/kickjs-cli-kit 0.0.0 → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Felix Orinda
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # @forinda/kickjs-cli-kit
2
+
3
+ The shared CLI-plugin contract for KickJS. Defines the types and helpers a package implements to ship `kick`-compatible commands, generators, and typegens — without depending on the full `@forinda/kickjs-cli`.
4
+
5
+ This is a tiny, dependency-free package (one `commander` peer). You only need it if you're **building** a CLI plugin; app authors never import it directly.
6
+
7
+ ## Why this package exists
8
+
9
+ The kick CLI mounts first-party plugins (the database tooling, for example). If those packages imported `defineCliPlugin` from `@forinda/kickjs-cli` to describe their commands, that would form a dependency cycle — the CLI already depends on them. Hoisting the **contract** into a standalone package both sides import breaks the cycle:
10
+
11
+ ```
12
+ @forinda/kickjs-cli ─┐
13
+ ├─► @forinda/kickjs-cli-kit (contract only)
14
+ @forinda/kickjs-db ─┘
15
+ ```
16
+
17
+ `@forinda/kickjs-cli` re-exports the whole contract, so `import { defineCliPlugin } from '@forinda/kickjs-cli'` keeps working for app-side `kick.config.ts` plugins.
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ pnpm add @forinda/kickjs-cli-kit commander
23
+ ```
24
+
25
+ `commander` is a peer dependency (the host CLI provides the `Command` your plugin registers against).
26
+
27
+ ## Quick start
28
+
29
+ ### A CLI plugin
30
+
31
+ ```ts
32
+ import { defineCliPlugin } from '@forinda/kickjs-cli-kit'
33
+
34
+ export const helloPlugin = defineCliPlugin({
35
+ name: 'my-org/hello',
36
+ register(program, ctx) {
37
+ program
38
+ .command('hello <name>')
39
+ .description('Say hello')
40
+ .action((name: string) => {
41
+ console.log(`Hello, ${name}! (project: ${ctx.projectRoot})`)
42
+ })
43
+ },
44
+ })
45
+ ```
46
+
47
+ Mount it in `kick.config.ts`:
48
+
49
+ ```ts
50
+ import { defineConfig } from '@forinda/kickjs-cli'
51
+ import { helloPlugin } from './tools/hello-plugin'
52
+
53
+ export default defineConfig({ plugins: [helloPlugin] })
54
+ ```
55
+
56
+ ```bash
57
+ kick hello world
58
+ ```
59
+
60
+ ### A `kick g <name>` generator
61
+
62
+ ```ts
63
+ import { defineGenerator } from '@forinda/kickjs-cli-kit'
64
+
65
+ export default [
66
+ defineGenerator({
67
+ name: 'widget',
68
+ description: 'Scaffold a widget',
69
+ args: [{ name: 'name', required: true }],
70
+ files: (ctx) => [
71
+ {
72
+ path: `src/widgets/${ctx.kebab}.ts`,
73
+ content: `export class ${ctx.pascal}Widget {}\n`,
74
+ },
75
+ ],
76
+ }),
77
+ ]
78
+ ```
79
+
80
+ ## Contract surface
81
+
82
+ | Export | Purpose |
83
+ | ------------------------- | ------------------------------------------------------------------------------------- |
84
+ | `defineCliPlugin(p)` | Declare a CLI plugin: `name` + `register()` / `commands` / `typegens` / `generators`. |
85
+ | `defineGenerator(spec)` | Declare a `kick g <name>` scaffolder (returns the spec, typed). |
86
+ | `KickCliPlugin<TConfig>` | The plugin shape. `TConfig` is the host config type (`ctx.config`). |
87
+ | `KickCliPluginContext` | What `register()` receives: `cwd`, `projectRoot`, `config`, `log`. |
88
+ | `GeneratorSpec` + co. | `GeneratorContext` / `GeneratorFile` / `GeneratorArg` / `GeneratorFlag`. |
89
+ | `KickCommandDefinition` | A declarative shell-handler command (the `commands` field shape). |
90
+ | `CliTypegen` | Structural typegen shape (the CLI's `TypegenPlugin` satisfies it). |
91
+ | `KickPluginConflictError` | Thrown on duplicate plugin / command / typegen / generator ids. |
92
+
93
+ ## License
94
+
95
+ MIT © Felix Orinda
@@ -0,0 +1,238 @@
1
+
2
+ import { Command } from "commander";
3
+
4
+ //#region src/generators.d.ts
5
+ /**
6
+ * Plugin generator API per architecture.md §21.2.3 — lets first-party
7
+ * AND third-party packages ship `kick g <name>` scaffolders the same
8
+ * way the framework's built-in generators do.
9
+ *
10
+ * Plugins declare a discovery file in their `package.json`:
11
+ *
12
+ * ```json
13
+ * {
14
+ * "name": "@my-org/kickjs-cqrs",
15
+ * "kickjs": { "generators": "./dist/generators.js" }
16
+ * }
17
+ * ```
18
+ *
19
+ * The discovery file exports a typed manifest:
20
+ *
21
+ * ```ts
22
+ * import { defineGenerator } from '@forinda/kickjs-cli-kit'
23
+ *
24
+ * export default [
25
+ * defineGenerator({
26
+ * name: 'command',
27
+ * description: 'Generate a CQRS command + handler',
28
+ * args: [{ name: 'name', required: true }],
29
+ * files: (ctx) => [
30
+ * {
31
+ * path: `src/modules/${ctx.kebab}/commands/create-${ctx.kebab}.command.ts`,
32
+ * content: `// generated command for ${ctx.pascal}`,
33
+ * },
34
+ * ],
35
+ * }),
36
+ * ]
37
+ * ```
38
+ *
39
+ * `kick g command Order` then dispatches against the registered
40
+ * generator and writes the returned files relative to `cwd`.
41
+ */
42
+ /**
43
+ * Resolved naming variants + project context handed to a generator's
44
+ * `files()` factory. Keys mirror `TemplateContext` so first-party
45
+ * generators that rely on the same shape can be migrated to plugin
46
+ * generators without rewriting their templates.
47
+ */
48
+ interface GeneratorContext {
49
+ /** Raw name passed on the command line (`kick g drizzle-typegen UserPost` → `'UserPost'`). */
50
+ name: string;
51
+ /** PascalCase form (`UserPost`). */
52
+ pascal: string;
53
+ /** kebab-case form (`user-post`). */
54
+ kebab: string;
55
+ /** camelCase form (`userPost`). */
56
+ camel: string;
57
+ /** snake_case form (`user_post`). */
58
+ snake: string;
59
+ /** Pluralized PascalCase (`UserPosts`) — present when the project enables `pluralize`. */
60
+ pluralPascal?: string;
61
+ /** Pluralized kebab-case (`user-posts`). */
62
+ pluralKebab?: string;
63
+ /** Pluralized camelCase (`userPosts`). */
64
+ pluralCamel?: string;
65
+ /** Modules directory from `kick.config.ts` (default `'src/modules'`). */
66
+ modulesDir: string;
67
+ /**
68
+ * Working directory the CLI was invoked from. May be a nested subdirectory
69
+ * if the adopter ran `kick g ...` from `src/modules/foo/` — for "write
70
+ * files relative to the project" use {@link projectRoot} instead.
71
+ */
72
+ cwd: string;
73
+ /**
74
+ * Resolved project root — the nearest ancestor directory of {@link cwd}
75
+ * containing `kick.config.{ts,js,mjs,json}` (or `package.json` as a
76
+ * fallback). Always set; falls back to `cwd` when no marker is found.
77
+ *
78
+ * Use this when writing files that must land at a known location
79
+ * regardless of where the adopter typed the command. `kick g ...` from
80
+ * inside `src/modules/foo/` will still see `projectRoot` pointing at
81
+ * the directory that owns `kick.config.ts`.
82
+ */
83
+ projectRoot: string;
84
+ /** Positional arguments passed AFTER the name (e.g. `kick g command Order extra1 extra2` → `['extra1', 'extra2']`). */
85
+ args: string[];
86
+ /** Flag values from the command line — booleans for switches, strings for `--key value`. */
87
+ flags: Record<string, string | boolean>;
88
+ }
89
+ /** A single output file the generator wants written. */
90
+ interface GeneratorFile {
91
+ /**
92
+ * Output path. Relative paths resolve against `ctx.cwd`; absolute
93
+ * paths are used as-is. Parent directories are created automatically.
94
+ */
95
+ path: string;
96
+ /** File contents written verbatim (UTF-8). */
97
+ content: string;
98
+ }
99
+ /** CLI argument descriptor surfaced in `kick g --list` help. */
100
+ interface GeneratorArg {
101
+ name: string;
102
+ required?: boolean;
103
+ description?: string;
104
+ }
105
+ /** CLI flag descriptor — boolean unless `takesValue: true`. */
106
+ interface GeneratorFlag {
107
+ name: string;
108
+ alias?: string;
109
+ description?: string;
110
+ takesValue?: boolean;
111
+ }
112
+ /**
113
+ * Spec returned by {@link defineGenerator}. Plugin discovery files
114
+ * export `GeneratorSpec[]` as their default export.
115
+ */
116
+ interface GeneratorSpec {
117
+ /**
118
+ * Dispatch name — `kick g <name>` looks for an exact match against
119
+ * this string after the built-in generators are checked.
120
+ */
121
+ name: string;
122
+ /** Description shown in `kick g --list` and `--help`. */
123
+ description: string;
124
+ /** Optional argument descriptors — informational, surfaced in help output. */
125
+ args?: readonly GeneratorArg[];
126
+ /** Optional flag descriptors — informational, surfaced in help output. */
127
+ flags?: readonly GeneratorFlag[];
128
+ /** Build the output files for one invocation. May return a Promise. */
129
+ files(ctx: GeneratorContext): GeneratorFile[] | Promise<GeneratorFile[]>;
130
+ }
131
+ /**
132
+ * Identity factory — returns the spec verbatim. Exists for type
133
+ * inference and forward-compatibility (future fields can be added with
134
+ * defaults).
135
+ *
136
+ * @example
137
+ * ```ts
138
+ * import { defineGenerator } from '@forinda/kickjs-cli-kit'
139
+ *
140
+ * export default [
141
+ * defineGenerator({
142
+ * name: 'command',
143
+ * description: 'Generate a CQRS command + handler',
144
+ * files: (ctx) => [
145
+ * {
146
+ * path: `src/modules/${ctx.kebab}/commands/${ctx.kebab}.command.ts`,
147
+ * content: `// command for ${ctx.pascal}`,
148
+ * },
149
+ * ],
150
+ * }),
151
+ * ]
152
+ * ```
153
+ */
154
+ declare function defineGenerator(spec: GeneratorSpec): GeneratorSpec;
155
+ //#endregion
156
+ //#region src/index.d.ts
157
+ /**
158
+ * A declarative shell-handler command — the same shape as the
159
+ * `kick.config.ts > commands` field.
160
+ */
161
+ interface KickCommandDefinition {
162
+ /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen'). */
163
+ name: string;
164
+ /** Description shown in --help. */
165
+ description: string;
166
+ /**
167
+ * Shell command(s) to run. A single string or an array of sequential
168
+ * steps. Use `{args}` as a placeholder for forwarded CLI arguments.
169
+ */
170
+ steps: string | string[];
171
+ /** Optional aliases (e.g. ['migrate'] for 'db:migrate'). */
172
+ aliases?: string[];
173
+ }
174
+ /**
175
+ * Structural shape of a typegen plugin as seen by the CLI-plugin
176
+ * contract. The CLI's full `TypegenPlugin` satisfies this (the `ctx`
177
+ * parameter is intentionally `any` here so the kit doesn't depend on the
178
+ * CLI's `TypegenContext` / scanner types).
179
+ */
180
+ interface CliTypegen {
181
+ id: string;
182
+ inputs: string[];
183
+ outExtension?: string;
184
+ generate(ctx: any): Promise<string | null>;
185
+ }
186
+ /** A plugin generator paired with the plugin name that supplied it. */
187
+ interface DiscoveredGenerator {
188
+ source: string;
189
+ spec: GeneratorSpec;
190
+ }
191
+ /**
192
+ * Runtime context handed to a plugin's `register()`. Forward-compatible:
193
+ * new fields land here without changing the callback signature.
194
+ */
195
+ interface KickCliPluginContext<TConfig = unknown> {
196
+ /** Directory the CLI was invoked from (may be a nested subdirectory). */
197
+ cwd: string;
198
+ /**
199
+ * Resolved project root — the nearest ancestor with a
200
+ * `kick.config.{ts,js,mjs,json}` (or `package.json`). Prefer this over
201
+ * `cwd` for writing artifacts at a stable location.
202
+ */
203
+ projectRoot: string;
204
+ /** The loaded host config (the CLI passes its full config). */
205
+ config: TConfig | null;
206
+ log: (msg: string) => void;
207
+ /** Plugin-shipped generators merged by the host, threaded for register(). */
208
+ generators?: DiscoveredGenerator[];
209
+ }
210
+ /**
211
+ * A CLI plugin: contributes commands, programmatic command registration,
212
+ * typegens, and/or generators. Implemented by the CLI's built-ins and by
213
+ * adopter / first-party packages alike.
214
+ */
215
+ interface KickCliPlugin<TConfig = unknown> {
216
+ /** Stable identifier — used in conflict errors + de-dup. */
217
+ name: string;
218
+ /** Declarative shell-handler commands. */
219
+ commands?: KickCommandDefinition[];
220
+ /** Programmatic command registration, called once at CLI startup. */
221
+ register?: (program: Command, ctx: KickCliPluginContext<TConfig>) => void | Promise<void>;
222
+ /** Typegen plugins the host runs after its own pass. */
223
+ typegens?: CliTypegen[];
224
+ /** `kick g <name>` scaffolders. */
225
+ generators?: GeneratorSpec[];
226
+ }
227
+ /**
228
+ * Identity helper for type inference + parity with `definePlugin` /
229
+ * `defineAdapter`. Returns the plugin verbatim.
230
+ */
231
+ declare function defineCliPlugin<TConfig = unknown>(p: KickCliPlugin<TConfig>): KickCliPlugin<TConfig>;
232
+ /** Thrown when two plugins register the same plugin/command/typegen/generator id. */
233
+ declare class KickPluginConflictError extends Error {
234
+ constructor(kind: 'plugin' | 'command' | 'typegen' | 'generator', id: string, owners: string[]);
235
+ }
236
+ //#endregion
237
+ export { CliTypegen, DiscoveredGenerator, GeneratorArg, GeneratorContext, GeneratorFile, GeneratorFlag, GeneratorSpec, KickCliPlugin, KickCliPluginContext, KickCommandDefinition, KickPluginConflictError, defineCliPlugin, defineGenerator };
238
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/generators.ts","../src/index.ts"],"mappings":";;;;;;;AA4CA;;;;;;;;;;;;;;;;;;;;AA2CA;;;;;AAWA;;;;;;;;;AAOA;;;;;;AAAA,UA7DiB,gBAAA;EAiEf;EA/DA,IAAA;EA+DU;EA7DV,MAAA;EAoE4B;EAlE5B,KAAA;EA2EgB;EAzEhB,KAAA;EA6EW;EA3EX,KAAA;EA2EwD;EAzExD,YAAA;EAyEuD;EAvEvD,WAAA;EA+DA;EA7DA,WAAA;EAiEA;EA/DA,UAAA;EAiEA;;;;;EA3DA,GAAA;EA6DgD;;;;AA0BlD;;;;;;EA5EE,WAAA;EA4EiE;EA1EjE,IAAA;;EAEA,KAAA,EAAO,MAAA;AAAA;ACvDT;AAAA,UD2DiB,aAAA;;;;;EAKf,IAAA;ECrDA;EDuDA,OAAA;AAAA;AC9CF;AAAA,UDkDiB,YAAA;EACf,IAAA;EACA,QAAA;EACA,WAAA;AAAA;;UAIe,aAAA;EACf,IAAA;EACA,KAAA;EACA,WAAA;EACA,UAAA;AAAA;;;;;UAOe,aAAA;ECtDT;;;AAOR;EDoDE,IAAA;ECpDmC;EDsDnC,WAAA;ECtDoC;EDwDpC,IAAA,YAAgB,YAAA;EChDhB;EDkDA,KAAA,YAAiB,aAAA;EChDT;EDkDR,KAAA,CAAM,GAAA,EAAK,gBAAA,GAAmB,aAAA,KAAkB,OAAA,CAAQ,aAAA;AAAA;;;;;ACvC1D;;;;;;;;;;;;;;;;;;;iBDiEgB,eAAA,CAAgB,IAAA,EAAM,aAAA,GAAgB,aAAA;;;;;AApEtD;;UC3DiB,qBAAA;EDgEf;EC9DA,IAAA;EDoEe;EClEf,WAAA;;;;;EAKA,KAAA;EDgEW;EC9DX,OAAA;AAAA;;;;;;;UASe,UAAA;EACf,EAAA;EACA,MAAA;EACA,YAAA;EAKA,QAAA,CAAS,GAAA,QAAW,OAAA;AAAA;;UAIL,mBAAA;EACf,MAAA;EACA,IAAA,EAAM,aAAA;AAAA;;;;;UAOS,oBAAA;EDwDf;ECtDA,GAAA;EDwDA;;;;;EClDA,WAAA;EDoDgD;EClDhD,MAAA,EAAQ,OAAA;EACR,GAAA,GAAM,GAAA;EDiD+D;EC/CrE,UAAA,GAAa,mBAAA;AAAA;;;;;;UAQE,aAAA;EDiEkD;EC/DjE,IAAA;;EAEA,QAAA,GAAW,qBAAA;EAlEI;EAoEf,QAAA,IAAY,OAAA,EAAS,OAAA,EAAS,GAAA,EAAK,oBAAA,CAAqB,OAAA,aAAoB,OAAA;;EAE5E,QAAA,GAAW,UAAA;EApEX;EAsEA,UAAA,GAAa,aAAA;AAAA;;;;AApDf;iBA2DgB,eAAA,mBAAA,CACd,CAAA,EAAG,aAAA,CAAc,OAAA,IAChB,aAAA,CAAc,OAAA;;cAKJ,uBAAA,SAAgC,KAAA;EAC3C,WAAA,CAAY,IAAA,kDAAsD,EAAA,UAAY,MAAA;AAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @forinda/kickjs-cli-kit v0.1.1
3
+ *
4
+ * Copyright (c) Felix Orinda
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ function defineGenerator(spec){return spec}function defineCliPlugin(p){return p}var KickPluginConflictError=class extends Error{constructor(kind,id,owners){super(`Two plugins registered the same ${kind} '${id}': ${owners.join(`, `)}. Plugins must use unique ${kind} names.`),this.name=`KickPluginConflictError`}};export{KickPluginConflictError,defineCliPlugin,defineGenerator};
12
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/generators.ts","../src/index.ts"],"sourcesContent":["/**\n * Plugin generator API per architecture.md §21.2.3 — lets first-party\n * AND third-party packages ship `kick g <name>` scaffolders the same\n * way the framework's built-in generators do.\n *\n * Plugins declare a discovery file in their `package.json`:\n *\n * ```json\n * {\n * \"name\": \"@my-org/kickjs-cqrs\",\n * \"kickjs\": { \"generators\": \"./dist/generators.js\" }\n * }\n * ```\n *\n * The discovery file exports a typed manifest:\n *\n * ```ts\n * import { defineGenerator } from '@forinda/kickjs-cli-kit'\n *\n * export default [\n * defineGenerator({\n * name: 'command',\n * description: 'Generate a CQRS command + handler',\n * args: [{ name: 'name', required: true }],\n * files: (ctx) => [\n * {\n * path: `src/modules/${ctx.kebab}/commands/create-${ctx.kebab}.command.ts`,\n * content: `// generated command for ${ctx.pascal}`,\n * },\n * ],\n * }),\n * ]\n * ```\n *\n * `kick g command Order` then dispatches against the registered\n * generator and writes the returned files relative to `cwd`.\n */\n\n/**\n * Resolved naming variants + project context handed to a generator's\n * `files()` factory. Keys mirror `TemplateContext` so first-party\n * generators that rely on the same shape can be migrated to plugin\n * generators without rewriting their templates.\n */\nexport interface GeneratorContext {\n /** Raw name passed on the command line (`kick g drizzle-typegen UserPost` → `'UserPost'`). */\n name: string\n /** PascalCase form (`UserPost`). */\n pascal: string\n /** kebab-case form (`user-post`). */\n kebab: string\n /** camelCase form (`userPost`). */\n camel: string\n /** snake_case form (`user_post`). */\n snake: string\n /** Pluralized PascalCase (`UserPosts`) — present when the project enables `pluralize`. */\n pluralPascal?: string\n /** Pluralized kebab-case (`user-posts`). */\n pluralKebab?: string\n /** Pluralized camelCase (`userPosts`). */\n pluralCamel?: string\n /** Modules directory from `kick.config.ts` (default `'src/modules'`). */\n modulesDir: string\n /**\n * Working directory the CLI was invoked from. May be a nested subdirectory\n * if the adopter ran `kick g ...` from `src/modules/foo/` — for \"write\n * files relative to the project\" use {@link projectRoot} instead.\n */\n cwd: string\n /**\n * Resolved project root — the nearest ancestor directory of {@link cwd}\n * containing `kick.config.{ts,js,mjs,json}` (or `package.json` as a\n * fallback). Always set; falls back to `cwd` when no marker is found.\n *\n * Use this when writing files that must land at a known location\n * regardless of where the adopter typed the command. `kick g ...` from\n * inside `src/modules/foo/` will still see `projectRoot` pointing at\n * the directory that owns `kick.config.ts`.\n */\n projectRoot: string\n /** Positional arguments passed AFTER the name (e.g. `kick g command Order extra1 extra2` → `['extra1', 'extra2']`). */\n args: string[]\n /** Flag values from the command line — booleans for switches, strings for `--key value`. */\n flags: Record<string, string | boolean>\n}\n\n/** A single output file the generator wants written. */\nexport interface GeneratorFile {\n /**\n * Output path. Relative paths resolve against `ctx.cwd`; absolute\n * paths are used as-is. Parent directories are created automatically.\n */\n path: string\n /** File contents written verbatim (UTF-8). */\n content: string\n}\n\n/** CLI argument descriptor surfaced in `kick g --list` help. */\nexport interface GeneratorArg {\n name: string\n required?: boolean\n description?: string\n}\n\n/** CLI flag descriptor — boolean unless `takesValue: true`. */\nexport interface GeneratorFlag {\n name: string\n alias?: string\n description?: string\n takesValue?: boolean\n}\n\n/**\n * Spec returned by {@link defineGenerator}. Plugin discovery files\n * export `GeneratorSpec[]` as their default export.\n */\nexport interface GeneratorSpec {\n /**\n * Dispatch name — `kick g <name>` looks for an exact match against\n * this string after the built-in generators are checked.\n */\n name: string\n /** Description shown in `kick g --list` and `--help`. */\n description: string\n /** Optional argument descriptors — informational, surfaced in help output. */\n args?: readonly GeneratorArg[]\n /** Optional flag descriptors — informational, surfaced in help output. */\n flags?: readonly GeneratorFlag[]\n /** Build the output files for one invocation. May return a Promise. */\n files(ctx: GeneratorContext): GeneratorFile[] | Promise<GeneratorFile[]>\n}\n\n/**\n * Identity factory — returns the spec verbatim. Exists for type\n * inference and forward-compatibility (future fields can be added with\n * defaults).\n *\n * @example\n * ```ts\n * import { defineGenerator } from '@forinda/kickjs-cli-kit'\n *\n * export default [\n * defineGenerator({\n * name: 'command',\n * description: 'Generate a CQRS command + handler',\n * files: (ctx) => [\n * {\n * path: `src/modules/${ctx.kebab}/commands/${ctx.kebab}.command.ts`,\n * content: `// command for ${ctx.pascal}`,\n * },\n * ],\n * }),\n * ]\n * ```\n */\nexport function defineGenerator(spec: GeneratorSpec): GeneratorSpec {\n return spec\n}\n","/**\n * `@forinda/kickjs-cli-kit` — the shared CLI-plugin contract.\n *\n * Both `@forinda/kickjs-cli` and packages that want to ship CLI commands\n * (e.g. `@forinda/kickjs-db/cli`) implement these types. Keeping the\n * contract in a dependency-free package breaks the dependency cycle that\n * would form if a package depended on `@forinda/kickjs-cli` to get\n * `defineCliPlugin` while the CLI depended on that package.\n *\n * The contract deliberately keeps the deep cli types loose:\n * - `ctx.config` is generic (`TConfig`, default `unknown`) — the host CLI\n * passes its full config; consumers narrow as needed.\n * - `typegens` use {@link CliTypegen}, the structural shape the CLI's\n * `TypegenPlugin` satisfies, so the kit never imports the typegen\n * scanner.\n *\n * @module @forinda/kickjs-cli-kit\n */\n\nimport type { Command } from 'commander'\n\nexport * from './generators'\nimport type { GeneratorSpec } from './generators'\n\n/**\n * A declarative shell-handler command — the same shape as the\n * `kick.config.ts > commands` field.\n */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen'). */\n name: string\n /** Description shown in --help. */\n description: string\n /**\n * Shell command(s) to run. A single string or an array of sequential\n * steps. Use `{args}` as a placeholder for forwarded CLI arguments.\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate'). */\n aliases?: string[]\n}\n\n/**\n * Structural shape of a typegen plugin as seen by the CLI-plugin\n * contract. The CLI's full `TypegenPlugin` satisfies this (the `ctx`\n * parameter is intentionally `any` here so the kit doesn't depend on the\n * CLI's `TypegenContext` / scanner types).\n */\nexport interface CliTypegen {\n id: string\n inputs: string[]\n outExtension?: string\n // `ctx` is `any` so the kit doesn't depend on the CLI's TypegenContext;\n // the return matches the CLI's TypegenPlugin exactly so the two are\n // mutually assignable.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n generate(ctx: any): Promise<string | null>\n}\n\n/** A plugin generator paired with the plugin name that supplied it. */\nexport interface DiscoveredGenerator {\n source: string\n spec: GeneratorSpec\n}\n\n/**\n * Runtime context handed to a plugin's `register()`. Forward-compatible:\n * new fields land here without changing the callback signature.\n */\nexport interface KickCliPluginContext<TConfig = unknown> {\n /** Directory the CLI was invoked from (may be a nested subdirectory). */\n cwd: string\n /**\n * Resolved project root — the nearest ancestor with a\n * `kick.config.{ts,js,mjs,json}` (or `package.json`). Prefer this over\n * `cwd` for writing artifacts at a stable location.\n */\n projectRoot: string\n /** The loaded host config (the CLI passes its full config). */\n config: TConfig | null\n log: (msg: string) => void\n /** Plugin-shipped generators merged by the host, threaded for register(). */\n generators?: DiscoveredGenerator[]\n}\n\n/**\n * A CLI plugin: contributes commands, programmatic command registration,\n * typegens, and/or generators. Implemented by the CLI's built-ins and by\n * adopter / first-party packages alike.\n */\nexport interface KickCliPlugin<TConfig = unknown> {\n /** Stable identifier — used in conflict errors + de-dup. */\n name: string\n /** Declarative shell-handler commands. */\n commands?: KickCommandDefinition[]\n /** Programmatic command registration, called once at CLI startup. */\n register?: (program: Command, ctx: KickCliPluginContext<TConfig>) => void | Promise<void>\n /** Typegen plugins the host runs after its own pass. */\n typegens?: CliTypegen[]\n /** `kick g <name>` scaffolders. */\n generators?: GeneratorSpec[]\n}\n\n/**\n * Identity helper for type inference + parity with `definePlugin` /\n * `defineAdapter`. Returns the plugin verbatim.\n */\nexport function defineCliPlugin<TConfig = unknown>(\n p: KickCliPlugin<TConfig>,\n): KickCliPlugin<TConfig> {\n return p\n}\n\n/** Thrown when two plugins register the same plugin/command/typegen/generator id. */\nexport class KickPluginConflictError extends Error {\n constructor(kind: 'plugin' | 'command' | 'typegen' | 'generator', id: string, owners: string[]) {\n super(\n `Two plugins registered the same ${kind} '${id}': ${owners.join(', ')}. ` +\n `Plugins must use unique ${kind} names.`,\n )\n this.name = 'KickPluginConflictError'\n }\n}\n"],"mappings":";;;;;;;;;;AA2JA,SAAgB,gBAAgB,KAAoC,CAClE,OAAO,KCjDT,SAAgB,gBACd,EACwB,CACxB,OAAO,EAIT,IAAa,wBAAb,cAA6C,KAAM,CACjD,YAAY,KAAsD,GAAY,OAAkB,CAC9F,MACE,mCAAmC,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,KAAK,CAAC,4BACzC,KAAK,SACnC,CACD,KAAK,KAAO"}
package/package.json CHANGED
@@ -1,14 +1,62 @@
1
1
  {
2
2
  "name": "@forinda/kickjs-cli-kit",
3
- "version": "0.0.0",
4
- "description": "Placeholder for @forinda/kickjs-cli-kit",
5
- "main": "index.js",
6
- "scripts": {},
7
- "keywords": [],
8
- "author": "forinda (https://www.npmjs.com/~forinda)",
9
- "license": "UNLICENSED",
10
- "private": false,
3
+ "version": "0.1.1",
4
+ "description": "Shared CLI-plugin contract for KickJS — defineCliPlugin, defineGenerator, and the types CLI plugins implement",
5
+ "keywords": [
6
+ "kickjs",
7
+ "cli",
8
+ "plugin",
9
+ "generator",
10
+ "commander",
11
+ "typescript"
12
+ ],
13
+ "type": "module",
14
+ "main": "dist/index.mjs",
15
+ "types": "dist/index.d.mts",
16
+ "exports": {
17
+ ".": {
18
+ "import": "./dist/index.mjs",
19
+ "types": "./dist/index.d.mts"
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "dependencies": {},
28
+ "peerDependencies": {
29
+ "commander": ">=12.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@types/node": "^25.9.2",
33
+ "commander": "^14.0.2",
34
+ "tsdown": "^0.21.7",
35
+ "typescript": "^6.0.3"
36
+ },
11
37
  "publishConfig": {
12
38
  "access": "public"
39
+ },
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/forinda/kick-js.git",
43
+ "directory": "packages/cli-kit"
44
+ },
45
+ "homepage": "https://forinda.github.io/kick-js/",
46
+ "bugs": {
47
+ "url": "https://github.com/forinda/kick-js/issues"
48
+ },
49
+ "license": "MIT",
50
+ "author": "Felix Orinda",
51
+ "engines": {
52
+ "node": ">=20.0"
53
+ },
54
+ "scripts": {
55
+ "build": "tsdown",
56
+ "dev": "tsdown --watch",
57
+ "test": "vitest run --passWithNoTests",
58
+ "typecheck": "tsgo --noEmit",
59
+ "clean": "rm -rf dist .wireit",
60
+ "lint": "tsc --noEmit"
13
61
  }
14
62
  }
package/index.js DELETED
@@ -1 +0,0 @@
1
- // Placeholder