@maltty/cli 1.0.0-rc.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.
Files changed (109) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +88 -0
  3. package/bin/maltty.js +3 -0
  4. package/dist/_format-CeQhQTl5.js +23 -0
  5. package/dist/_format-CeQhQTl5.js.map +1 -0
  6. package/dist/attemptAsync-BdXzRSIT.js +42 -0
  7. package/dist/attemptAsync-BdXzRSIT.js.map +1 -0
  8. package/dist/chunk-DsIazq42.js +26 -0
  9. package/dist/commands/add/command.d.ts +7 -0
  10. package/dist/commands/add/command.d.ts.map +1 -0
  11. package/dist/commands/add/command.js +123 -0
  12. package/dist/commands/add/command.js.map +1 -0
  13. package/dist/commands/add/config.d.ts +7 -0
  14. package/dist/commands/add/config.d.ts.map +1 -0
  15. package/dist/commands/add/config.js +57 -0
  16. package/dist/commands/add/config.js.map +1 -0
  17. package/dist/commands/add/index.d.ts +7 -0
  18. package/dist/commands/add/index.d.ts.map +1 -0
  19. package/dist/commands/add/index.js +7 -0
  20. package/dist/commands/add/index.js.map +1 -0
  21. package/dist/commands/add/middleware.d.ts +7 -0
  22. package/dist/commands/add/middleware.d.ts.map +1 -0
  23. package/dist/commands/add/middleware.js +88 -0
  24. package/dist/commands/add/middleware.js.map +1 -0
  25. package/dist/commands/build.d.ts +15 -0
  26. package/dist/commands/build.d.ts.map +1 -0
  27. package/dist/commands/build.js +246 -0
  28. package/dist/commands/build.js.map +1 -0
  29. package/dist/commands/commands.d.ts +14 -0
  30. package/dist/commands/commands.d.ts.map +1 -0
  31. package/dist/commands/commands.js +189 -0
  32. package/dist/commands/commands.js.map +1 -0
  33. package/dist/commands/dev.d.ts +13 -0
  34. package/dist/commands/dev.d.ts.map +1 -0
  35. package/dist/commands/dev.js +58 -0
  36. package/dist/commands/dev.js.map +1 -0
  37. package/dist/commands/doctor.d.ts +13 -0
  38. package/dist/commands/doctor.d.ts.map +1 -0
  39. package/dist/commands/doctor.js +658 -0
  40. package/dist/commands/doctor.js.map +1 -0
  41. package/dist/commands/init.d.ts +7 -0
  42. package/dist/commands/init.d.ts.map +1 -0
  43. package/dist/commands/init.js +305 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/commands/run.d.ts +19 -0
  46. package/dist/commands/run.d.ts.map +1 -0
  47. package/dist/commands/run.js +478 -0
  48. package/dist/commands/run.js.map +1 -0
  49. package/dist/commands/stories.d.ts +11 -0
  50. package/dist/commands/stories.d.ts.map +1 -0
  51. package/dist/commands/stories.js +22 -0
  52. package/dist/commands/stories.js.map +1 -0
  53. package/dist/config-helpers-pv_2Spux.js +15 -0
  54. package/dist/config-helpers-pv_2Spux.js.map +1 -0
  55. package/dist/defu-BBwssjW3.js +192 -0
  56. package/dist/defu-BBwssjW3.js.map +1 -0
  57. package/dist/detect-AOq1ehTE.js +61 -0
  58. package/dist/detect-AOq1ehTE.js.map +1 -0
  59. package/dist/dist-DW_gRP7_.js +1119 -0
  60. package/dist/dist-DW_gRP7_.js.map +1 -0
  61. package/dist/dist-Xa07jNxS.js +15617 -0
  62. package/dist/dist-Xa07jNxS.js.map +1 -0
  63. package/dist/index.d.ts +1 -0
  64. package/dist/index.js +46 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/jiti-CxWlVmZ_.js +5458 -0
  67. package/dist/jiti-CxWlVmZ_.js.map +1 -0
  68. package/dist/json-D7WbuVK1.js +43 -0
  69. package/dist/json-D7WbuVK1.js.map +1 -0
  70. package/dist/json5-z-PGDMyy.js +777 -0
  71. package/dist/json5-z-PGDMyy.js.map +1 -0
  72. package/dist/jsonc-DqZkfC3S.js +401 -0
  73. package/dist/jsonc-DqZkfC3S.js.map +1 -0
  74. package/dist/jsonc-KADMdSjU.js +2 -0
  75. package/dist/lib/templates/command/command.ts.liquid +12 -0
  76. package/dist/lib/templates/config/config.ts.liquid +16 -0
  77. package/dist/lib/templates/middleware/middleware.ts.liquid +9 -0
  78. package/dist/lib/templates/project/gitignore.liquid +3 -0
  79. package/dist/lib/templates/project/maltty.config.ts.liquid +6 -0
  80. package/dist/lib/templates/project/package.json.liquid +30 -0
  81. package/dist/lib/templates/project/src/commands/hello.ts.liquid +12 -0
  82. package/dist/lib/templates/project/src/config.ts.liquid +16 -0
  83. package/dist/lib/templates/project/src/index.ts.liquid +13 -0
  84. package/dist/lib/templates/project/tsconfig.json.liquid +19 -0
  85. package/dist/lib/templates/project/vitest.config.ts.liquid +8 -0
  86. package/dist/main-C_8x2aB3.js +274 -0
  87. package/dist/main-C_8x2aB3.js.map +1 -0
  88. package/dist/manifest-BIKVDJML.js +112 -0
  89. package/dist/manifest-BIKVDJML.js.map +1 -0
  90. package/dist/multipart-parser-MNkxNO83.js +174 -0
  91. package/dist/multipart-parser-MNkxNO83.js.map +1 -0
  92. package/dist/node-C91xGGqn.js +644 -0
  93. package/dist/node-C91xGGqn.js.map +1 -0
  94. package/dist/node-Drmc03fL.js +3973 -0
  95. package/dist/node-Drmc03fL.js.map +1 -0
  96. package/dist/ohash-BPoV4zBH.js +185 -0
  97. package/dist/ohash-BPoV4zBH.js.map +1 -0
  98. package/dist/pnpm-workspace.yaml +26 -0
  99. package/dist/toml-LuHsHQtV.js +646 -0
  100. package/dist/toml-LuHsHQtV.js.map +1 -0
  101. package/dist/utils-DlIJNGLQ.js +1905 -0
  102. package/dist/utils-DlIJNGLQ.js.map +1 -0
  103. package/dist/validate-C_SXBoLq.js +18 -0
  104. package/dist/validate-C_SXBoLq.js.map +1 -0
  105. package/dist/write-CSwG4Stj.js +152 -0
  106. package/dist/write-CSwG4Stj.js.map +1 -0
  107. package/dist/yaml-BS9RDuUr.js +1067 -0
  108. package/dist/yaml-BS9RDuUr.js.map +1 -0
  109. package/package.json +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ByteFarm
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,88 @@
1
+ # @maltty/cli
2
+
3
+ DX companion CLI for the maltty framework. Provides scaffolding, build tooling, a dev server, and diagnostics for maltty-based CLI projects.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add -D @maltty/cli
9
+ ```
10
+
11
+ This package installs the `maltty` binary.
12
+
13
+ ## Commands
14
+
15
+ ### `maltty init`
16
+
17
+ Scaffold a new maltty CLI project with a recommended directory structure, config file, and starter command.
18
+
19
+ ```bash
20
+ maltty init
21
+ ```
22
+
23
+ ### `maltty build`
24
+
25
+ Bundle your CLI using tsdown. Reads `maltty.config.ts` for entry point, output directory, and compile targets.
26
+
27
+ ```bash
28
+ maltty build
29
+ maltty build --compile # produce standalone binaries
30
+ ```
31
+
32
+ ### `maltty dev`
33
+
34
+ Start a dev server that watches for changes and rebuilds automatically.
35
+
36
+ ```bash
37
+ maltty dev
38
+ ```
39
+
40
+ ### `maltty commands`
41
+
42
+ List all registered commands in the project.
43
+
44
+ ```bash
45
+ maltty commands
46
+ ```
47
+
48
+ ### `maltty doctor`
49
+
50
+ Run diagnostics to verify your project setup, dependencies, and configuration.
51
+
52
+ ```bash
53
+ maltty doctor
54
+ ```
55
+
56
+ ### `maltty stories`
57
+
58
+ Launch the stories viewer TUI for browsing and previewing component stories in the terminal. Discovers `.stories.tsx` files in the project and renders them with an interactive props editor.
59
+
60
+ ```bash
61
+ maltty stories
62
+ maltty stories --include "src/components/**/*.stories.tsx"
63
+ ```
64
+
65
+ ## Configuration
66
+
67
+ The CLI reads from `maltty.config.ts` in your project root:
68
+
69
+ ```ts
70
+ import { defineConfig } from 'maltty/config'
71
+
72
+ export default defineConfig({
73
+ entry: './src/index.ts',
74
+ commands: './src/commands',
75
+ build: {
76
+ out: './dist',
77
+ target: 'node18',
78
+ minify: false,
79
+ },
80
+ compile: {
81
+ targets: ['darwin-arm64', 'linux-x64'],
82
+ },
83
+ })
84
+ ```
85
+
86
+ ## License
87
+
88
+ MIT -- [GitHub](https://github.com/thebytefarm/maltty)
package/bin/maltty.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ import '../dist/index.js'
@@ -0,0 +1,23 @@
1
+ //#region ../../node_modules/.pnpm/confbox@0.2.4/node_modules/confbox/dist/_chunks/_format.mjs
2
+ const t = Symbol.for(`__confbox_fmt__`), n = /^(\s+)/, r = /(\s+)$/;
3
+ function i(e, t = {}) {
4
+ return {
5
+ sample: t.indent === void 0 && t.preserveIndentation !== !1 && e.slice(0, t?.sampleSize || 1024),
6
+ whiteSpace: t.preserveWhitespace === !1 ? void 0 : {
7
+ start: n.exec(e)?.[0] || ``,
8
+ end: r.exec(e)?.[0] || ``
9
+ }
10
+ };
11
+ }
12
+ function a(e, n, r) {
13
+ !n || typeof n != `object` || Object.defineProperty(n, t, {
14
+ enumerable: !1,
15
+ configurable: !0,
16
+ writable: !0,
17
+ value: i(e, r)
18
+ });
19
+ }
20
+ //#endregion
21
+ export { a as t };
22
+
23
+ //# sourceMappingURL=_format-CeQhQTl5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_format-CeQhQTl5.js","names":[],"sources":["../../../node_modules/.pnpm/confbox@0.2.4/node_modules/confbox/dist/_chunks/_format.mjs"],"sourcesContent":["import{t as e}from\"./libs/detect-indent.mjs\";const t=Symbol.for(`__confbox_fmt__`),n=/^(\\s+)/,r=/(\\s+)$/;function i(e,t={}){return{sample:t.indent===void 0&&t.preserveIndentation!==!1&&e.slice(0,t?.sampleSize||1024),whiteSpace:t.preserveWhitespace===!1?void 0:{start:n.exec(e)?.[0]||``,end:r.exec(e)?.[0]||``}}}function a(e,n,r){!n||typeof n!=`object`||Object.defineProperty(n,t,{enumerable:!1,configurable:!0,writable:!0,value:i(e,r)})}function o(n,r){if(!n||typeof n!=`object`||!(t in n))return{indent:r?.indent??2,whitespace:{start:``,end:``}};let i=n[t];return{indent:r?.indent||e(i.sample||``).indent,whitespace:i.whiteSpace||{start:``,end:``}}}export{a as n,o as t};"],"x_google_ignoreList":[0],"mappings":";AAA6C,MAAM,IAAE,OAAO,IAAI,kBAAkB,EAAC,IAAE,UAAS,IAAE;AAAS,SAAS,EAAE,GAAE,IAAE,EAAE,EAAC;AAAC,QAAM;EAAC,QAAO,EAAE,WAAS,KAAK,KAAG,EAAE,wBAAsB,CAAC,KAAG,EAAE,MAAM,GAAE,GAAG,cAAY,KAAK;EAAC,YAAW,EAAE,uBAAqB,CAAC,IAAE,KAAK,IAAE;GAAC,OAAM,EAAE,KAAK,EAAE,GAAG,MAAI;GAAG,KAAI,EAAE,KAAK,EAAE,GAAG,MAAI;GAAG;EAAC;;AAAC,SAAS,EAAE,GAAE,GAAE,GAAE;AAAC,EAAC,KAAG,OAAO,KAAG,YAAU,OAAO,eAAe,GAAE,GAAE;EAAC,YAAW,CAAC;EAAE,cAAa,CAAC;EAAE,UAAS,CAAC;EAAE,OAAM,EAAE,GAAE,EAAE;EAAC,CAAC"}
@@ -0,0 +1,42 @@
1
+ //#region ../utils/dist/result-D_NYcfr2.js
2
+ /**
3
+ * Normalize an unknown caught value into an Error instance.
4
+ *
5
+ * If already an Error, returns it as-is. Otherwise wraps via `new Error(String(value))`.
6
+ *
7
+ * @param value - The unknown value to normalize.
8
+ * @returns An Error instance.
9
+ */
10
+ function toError(value) {
11
+ if (value instanceof Error) return value;
12
+ return new Error(String(value));
13
+ }
14
+ function ok(value) {
15
+ return [null, value];
16
+ }
17
+ /**
18
+ * Construct a failure Result tuple.
19
+ *
20
+ * Coerces any value to an `Error` via {@link toError} and returns `[Error, null]`.
21
+ * For domain-specific error types (e.g. `AuthError`, `IconsError`), use raw
22
+ * tuple literals instead: `[domainError, null] as const`.
23
+ *
24
+ * @param error - The error value (coerced to Error).
25
+ * @returns A Result tuple `[Error, null]`.
26
+ */
27
+ function err(error) {
28
+ return [toError(error), null];
29
+ }
30
+ //#endregion
31
+ //#region ../../node_modules/.pnpm/es-toolkit@1.46.1/node_modules/es-toolkit/dist/util/attemptAsync.mjs
32
+ async function attemptAsync(func) {
33
+ try {
34
+ return [null, await func()];
35
+ } catch (error) {
36
+ return [error, null];
37
+ }
38
+ }
39
+ //#endregion
40
+ export { toError as i, err as n, ok as r, attemptAsync as t };
41
+
42
+ //# sourceMappingURL=attemptAsync-BdXzRSIT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attemptAsync-BdXzRSIT.js","names":[],"sources":["../../utils/dist/result-D_NYcfr2.js","../../../node_modules/.pnpm/es-toolkit@1.46.1/node_modules/es-toolkit/dist/util/attemptAsync.mjs"],"sourcesContent":["//#region src/fp/transform.ts\n/**\n* Normalize an unknown caught value into an Error instance.\n*\n* If already an Error, returns it as-is. Otherwise wraps via `new Error(String(value))`.\n*\n* @param value - The unknown value to normalize.\n* @returns An Error instance.\n*/\nfunction toError(value) {\n\tif (value instanceof Error) return value;\n\treturn new Error(String(value));\n}\n//#endregion\n//#region src/fp/result.ts\nfunction ok(value) {\n\treturn [null, value];\n}\n/**\n* Construct a failure Result tuple.\n*\n* Coerces any value to an `Error` via {@link toError} and returns `[Error, null]`.\n* For domain-specific error types (e.g. `AuthError`, `IconsError`), use raw\n* tuple literals instead: `[domainError, null] as const`.\n*\n* @param error - The error value (coerced to Error).\n* @returns A Result tuple `[Error, null]`.\n*/\nfunction err(error) {\n\treturn [toError(error), null];\n}\n//#endregion\nexport { ok as n, toError as r, err as t };\n\n//# sourceMappingURL=result-D_NYcfr2.js.map","async function attemptAsync(func) {\n try {\n const result = await func();\n return [null, result];\n }\n catch (error) {\n return [error, null];\n }\n}\n\nexport { attemptAsync };\n"],"x_google_ignoreList":[1],"mappings":";;;;;;;;;AASA,SAAS,QAAQ,OAAO;AACvB,KAAI,iBAAiB,MAAO,QAAO;AACnC,QAAO,IAAI,MAAM,OAAO,MAAM,CAAC;;AAIhC,SAAS,GAAG,OAAO;AAClB,QAAO,CAAC,MAAM,MAAM;;;;;;;;;;;;AAYrB,SAAS,IAAI,OAAO;AACnB,QAAO,CAAC,QAAQ,MAAM,EAAE,KAAK;;;;AC7B9B,eAAe,aAAa,MAAM;AAC9B,KAAI;AAEA,SAAO,CAAC,MADO,MAAM,MAAM,CACN;UAElB,OAAO;AACV,SAAO,CAAC,OAAO,KAAK"}
@@ -0,0 +1,26 @@
1
+ import { createRequire } from "node:module";
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
21
+ value: mod,
22
+ enumerable: true
23
+ }) : target, mod));
24
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
25
+ //#endregion
26
+ export { __require as n, __toESM as r, __commonJSMin as t };
@@ -0,0 +1,7 @@
1
+ import { Command } from "maltty";
2
+
3
+ //#region src/commands/add/command.d.ts
4
+ declare const addCommandCommand: Command;
5
+ //#endregion
6
+ export { addCommandCommand as default };
7
+ //# sourceMappingURL=command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.d.ts","names":[],"sources":["../../../src/commands/add/command.ts"],"mappings":";;;cAqBM,iBAAA,EAAmB,OAAA"}
@@ -0,0 +1,123 @@
1
+ import { n as loadConfig } from "../../utils-DlIJNGLQ.js";
2
+ import { n as renderTemplate, t as writeFiles } from "../../write-CSwG4Stj.js";
3
+ import { t as isKebabCase } from "../../validate-C_SXBoLq.js";
4
+ import { t as detectProject } from "../../detect-AOq1ehTE.js";
5
+ import { command } from "maltty";
6
+ import { join } from "node:path";
7
+ import { z } from "zod";
8
+ //#region src/commands/add/command.ts
9
+ const addCommandCommand = command({
10
+ options: z.object({
11
+ args: z.boolean().describe("Include args schema").optional(),
12
+ description: z.string().describe("Command description").optional(),
13
+ name: z.string().describe("Command name (kebab-case)").optional()
14
+ }),
15
+ description: "Add a new command to your project",
16
+ handler: async (ctx) => {
17
+ const [detectError, project] = await detectProject(process.cwd());
18
+ if (detectError) return ctx.fail(detectError.message);
19
+ if (!project) return ctx.fail("Not in a maltty project. Run `maltty init` first.");
20
+ const [, configResult] = await loadConfig({ cwd: project.rootDir });
21
+ const commandName = await resolveCommandName(ctx);
22
+ const commandDescription = await resolveDescription(ctx);
23
+ const includeArgs = await resolveIncludeArgs(ctx);
24
+ ctx.status.spinner.start("Generating command...");
25
+ const [renderError, rendered] = await renderTemplate({
26
+ templateDir: join(import.meta.dirname, "..", "..", "lib", "templates", "command"),
27
+ variables: {
28
+ commandName,
29
+ description: commandDescription,
30
+ includeArgs
31
+ }
32
+ });
33
+ if (renderError) {
34
+ ctx.status.spinner.stop("Failed");
35
+ return ctx.fail(renderError.message);
36
+ }
37
+ const outputDir = resolveCommandsDir(configResult, project.rootDir);
38
+ const [writeError, result] = await writeFiles({
39
+ files: rendered.map((file) => ({
40
+ content: file.content,
41
+ relativePath: file.relativePath.replace("command.ts", `${commandName}.ts`)
42
+ })),
43
+ outputDir,
44
+ overwrite: false
45
+ });
46
+ if (writeError) {
47
+ ctx.status.spinner.stop("Failed");
48
+ return ctx.fail(writeError.message);
49
+ }
50
+ ctx.status.spinner.stop("Command created!");
51
+ const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
52
+ if (summary.length > 0) ctx.log.raw(summary);
53
+ }
54
+ });
55
+ /**
56
+ * Resolve the command name from args or prompt.
57
+ *
58
+ * @param ctx - Command context.
59
+ * @returns The validated command name.
60
+ * @private
61
+ */
62
+ async function resolveCommandName(ctx) {
63
+ if (ctx.args.name) {
64
+ if (!isKebabCase(ctx.args.name)) return ctx.fail("Command name must be kebab-case (e.g. deploy)");
65
+ return ctx.args.name;
66
+ }
67
+ return ctx.prompts.text({
68
+ message: "Command name",
69
+ placeholder: "deploy",
70
+ validate: (value) => {
71
+ if (value === void 0 || !isKebabCase(value)) return "Must be kebab-case (e.g. deploy)";
72
+ }
73
+ });
74
+ }
75
+ /**
76
+ * Resolve the command description from args or prompt.
77
+ *
78
+ * @param ctx - Command context.
79
+ * @returns The command description string.
80
+ * @private
81
+ */
82
+ async function resolveDescription(ctx) {
83
+ if (ctx.args.description) return ctx.args.description;
84
+ return ctx.prompts.text({
85
+ defaultValue: "",
86
+ message: "Description",
87
+ placeholder: "What does this command do?"
88
+ });
89
+ }
90
+ /**
91
+ * Resolve whether to include args from args or prompt.
92
+ *
93
+ * @param ctx - Command context.
94
+ * @returns True when the command should include a zod args schema.
95
+ * @private
96
+ */
97
+ async function resolveIncludeArgs(ctx) {
98
+ if (ctx.args.args !== void 0) return ctx.args.args;
99
+ return ctx.prompts.confirm({
100
+ initialValue: true,
101
+ message: "Include args schema?"
102
+ });
103
+ }
104
+ /**
105
+ * Resolve the commands output directory from the maltty config.
106
+ *
107
+ * Uses the `commands` field from `maltty.config.ts` when available,
108
+ * falling back to the maltty default of `'commands'`.
109
+ *
110
+ * @param configResult - The loaded config result, or null when loading failed.
111
+ * @param rootDir - The project root directory.
112
+ * @returns The absolute path to the commands directory.
113
+ * @private
114
+ */
115
+ function resolveCommandsDir(configResult, rootDir) {
116
+ const DEFAULT_COMMANDS = "commands";
117
+ if (configResult) return join(rootDir, configResult.config.commands ?? DEFAULT_COMMANDS);
118
+ return join(rootDir, DEFAULT_COMMANDS);
119
+ }
120
+ //#endregion
121
+ export { addCommandCommand as default };
122
+
123
+ //# sourceMappingURL=command.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command.js","names":[],"sources":["../../../src/commands/add/command.ts"],"sourcesContent":["import { join } from 'node:path'\n\nimport { loadConfig } from '@maltty/config/utils'\nimport type { LoadConfigResult } from '@maltty/config/utils'\nimport { command } from 'maltty'\nimport type { Command, CommandContext } from 'maltty'\nimport { z } from 'zod'\n\nimport { detectProject } from '../../lib/detect.js'\nimport { renderTemplate } from '../../lib/render.js'\nimport { isKebabCase } from '../../lib/validate.js'\nimport { writeFiles } from '../../lib/write.js'\n\nconst options = z.object({\n args: z.boolean().describe('Include args schema').optional(),\n description: z.string().describe('Command description').optional(),\n name: z.string().describe('Command name (kebab-case)').optional(),\n})\n\ntype AddCommandArgs = z.infer<typeof options>\n\nconst addCommandCommand: Command = command({\n options,\n description: 'Add a new command to your project',\n handler: async (ctx: CommandContext<AddCommandArgs>) => {\n const cwd = process.cwd()\n\n const [detectError, project] = await detectProject(cwd)\n if (detectError) {\n return ctx.fail(detectError.message)\n }\n if (!project) {\n return ctx.fail('Not in a maltty project. Run `maltty init` first.')\n }\n\n const [, configResult] = await loadConfig({ cwd: project.rootDir })\n\n const commandName = await resolveCommandName(ctx)\n const commandDescription = await resolveDescription(ctx)\n const includeArgs = await resolveIncludeArgs(ctx)\n\n ctx.status.spinner.start('Generating command...')\n\n const templateDir = join(import.meta.dirname, '..', '..', 'lib', 'templates', 'command')\n const [renderError, rendered] = await renderTemplate({\n templateDir,\n variables: { commandName, description: commandDescription, includeArgs },\n })\n\n if (renderError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(renderError.message)\n }\n\n const outputDir = resolveCommandsDir(configResult, project.rootDir)\n const files = rendered.map((file) => ({\n content: file.content,\n relativePath: file.relativePath.replace('command.ts', `${commandName}.ts`),\n }))\n\n const [writeError, result] = await writeFiles({ files, outputDir, overwrite: false })\n\n if (writeError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(writeError.message)\n }\n\n ctx.status.spinner.stop('Command created!')\n\n const lines = [\n ...result.written.map((file) => ` created ${file}`),\n ...result.skipped.map((file) => ` skipped ${file} (already exists)`),\n ]\n const summary = lines.join('\\n')\n if (summary.length > 0) {\n ctx.log.raw(summary)\n }\n },\n})\n\nexport default addCommandCommand\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the command name from args or prompt.\n *\n * @param ctx - Command context.\n * @returns The validated command name.\n * @private\n */\nasync function resolveCommandName(ctx: CommandContext<AddCommandArgs>): Promise<string> {\n if (ctx.args.name) {\n if (!isKebabCase(ctx.args.name)) {\n return ctx.fail('Command name must be kebab-case (e.g. deploy)')\n }\n return ctx.args.name\n }\n return ctx.prompts.text({\n message: 'Command name',\n placeholder: 'deploy',\n validate: (value: string | undefined) => {\n if (value === undefined || !isKebabCase(value)) {\n return 'Must be kebab-case (e.g. deploy)'\n }\n return undefined\n },\n })\n}\n\n/**\n * Resolve the command description from args or prompt.\n *\n * @param ctx - Command context.\n * @returns The command description string.\n * @private\n */\nasync function resolveDescription(ctx: CommandContext<AddCommandArgs>): Promise<string> {\n if (ctx.args.description) {\n return ctx.args.description\n }\n return ctx.prompts.text({\n defaultValue: '',\n message: 'Description',\n placeholder: 'What does this command do?',\n })\n}\n\n/**\n * Resolve whether to include args from args or prompt.\n *\n * @param ctx - Command context.\n * @returns True when the command should include a zod args schema.\n * @private\n */\nasync function resolveIncludeArgs(ctx: CommandContext<AddCommandArgs>): Promise<boolean> {\n if (ctx.args.args !== undefined) {\n return ctx.args.args\n }\n return ctx.prompts.confirm({\n initialValue: true,\n message: 'Include args schema?',\n })\n}\n\n/**\n * Resolve the commands output directory from the maltty config.\n *\n * Uses the `commands` field from `maltty.config.ts` when available,\n * falling back to the maltty default of `'commands'`.\n *\n * @param configResult - The loaded config result, or null when loading failed.\n * @param rootDir - The project root directory.\n * @returns The absolute path to the commands directory.\n * @private\n */\nfunction resolveCommandsDir(configResult: LoadConfigResult | null, rootDir: string): string {\n const DEFAULT_COMMANDS = 'commands'\n\n if (configResult) {\n return join(rootDir, configResult.config.commands ?? DEFAULT_COMMANDS)\n }\n\n return join(rootDir, DEFAULT_COMMANDS)\n}\n"],"mappings":";;;;;;;;AAqBA,MAAM,oBAA6B,QAAQ;CACzC,SATc,EAAE,OAAO;EACvB,MAAM,EAAE,SAAS,CAAC,SAAS,sBAAsB,CAAC,UAAU;EAC5D,aAAa,EAAE,QAAQ,CAAC,SAAS,sBAAsB,CAAC,UAAU;EAClE,MAAM,EAAE,QAAQ,CAAC,SAAS,4BAA4B,CAAC,UAAU;EAClE,CAAC;CAMA,aAAa;CACb,SAAS,OAAO,QAAwC;EAGtD,MAAM,CAAC,aAAa,WAAW,MAAM,cAFzB,QAAQ,KAAK,CAE8B;AACvD,MAAI,YACF,QAAO,IAAI,KAAK,YAAY,QAAQ;AAEtC,MAAI,CAAC,QACH,QAAO,IAAI,KAAK,oDAAoD;EAGtE,MAAM,GAAG,gBAAgB,MAAM,WAAW,EAAE,KAAK,QAAQ,SAAS,CAAC;EAEnE,MAAM,cAAc,MAAM,mBAAmB,IAAI;EACjD,MAAM,qBAAqB,MAAM,mBAAmB,IAAI;EACxD,MAAM,cAAc,MAAM,mBAAmB,IAAI;AAEjD,MAAI,OAAO,QAAQ,MAAM,wBAAwB;EAGjD,MAAM,CAAC,aAAa,YAAY,MAAM,eAAe;GACnD,aAFkB,KAAK,OAAO,KAAK,SAAS,MAAM,MAAM,OAAO,aAAa,UAAU;GAGtF,WAAW;IAAE;IAAa,aAAa;IAAoB;IAAa;GACzE,CAAC;AAEF,MAAI,aAAa;AACf,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,YAAY,QAAQ;;EAGtC,MAAM,YAAY,mBAAmB,cAAc,QAAQ,QAAQ;EAMnE,MAAM,CAAC,YAAY,UAAU,MAAM,WAAW;GAAE,OALlC,SAAS,KAAK,UAAU;IACpC,SAAS,KAAK;IACd,cAAc,KAAK,aAAa,QAAQ,cAAc,GAAG,YAAY,KAAK;IAC3E,EAAE;GAEoD;GAAW,WAAW;GAAO,CAAC;AAErF,MAAI,YAAY;AACd,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,WAAW,QAAQ;;AAGrC,MAAI,OAAO,QAAQ,KAAK,mBAAmB;EAM3C,MAAM,UAJQ,CACZ,GAAG,OAAO,QAAQ,KAAK,SAAS,aAAa,OAAO,EACpD,GAAG,OAAO,QAAQ,KAAK,SAAS,aAAa,KAAK,mBAAmB,CACtE,CACqB,KAAK,KAAK;AAChC,MAAI,QAAQ,SAAS,EACnB,KAAI,IAAI,IAAI,QAAQ;;CAGzB,CAAC;;;;;;;;AAeF,eAAe,mBAAmB,KAAsD;AACtF,KAAI,IAAI,KAAK,MAAM;AACjB,MAAI,CAAC,YAAY,IAAI,KAAK,KAAK,CAC7B,QAAO,IAAI,KAAK,gDAAgD;AAElE,SAAO,IAAI,KAAK;;AAElB,QAAO,IAAI,QAAQ,KAAK;EACtB,SAAS;EACT,aAAa;EACb,WAAW,UAA8B;AACvC,OAAI,UAAU,KAAA,KAAa,CAAC,YAAY,MAAM,CAC5C,QAAO;;EAIZ,CAAC;;;;;;;;;AAUJ,eAAe,mBAAmB,KAAsD;AACtF,KAAI,IAAI,KAAK,YACX,QAAO,IAAI,KAAK;AAElB,QAAO,IAAI,QAAQ,KAAK;EACtB,cAAc;EACd,SAAS;EACT,aAAa;EACd,CAAC;;;;;;;;;AAUJ,eAAe,mBAAmB,KAAuD;AACvF,KAAI,IAAI,KAAK,SAAS,KAAA,EACpB,QAAO,IAAI,KAAK;AAElB,QAAO,IAAI,QAAQ,QAAQ;EACzB,cAAc;EACd,SAAS;EACV,CAAC;;;;;;;;;;;;;AAcJ,SAAS,mBAAmB,cAAuC,SAAyB;CAC1F,MAAM,mBAAmB;AAEzB,KAAI,aACF,QAAO,KAAK,SAAS,aAAa,OAAO,YAAY,iBAAiB;AAGxE,QAAO,KAAK,SAAS,iBAAiB"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "maltty";
2
+
3
+ //#region src/commands/add/config.d.ts
4
+ declare const addConfigCommand: Command;
5
+ //#endregion
6
+ export { addConfigCommand as default };
7
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","names":[],"sources":["../../../src/commands/add/config.ts"],"mappings":";;;cAUM,gBAAA,EAAkB,OAAA"}
@@ -0,0 +1,57 @@
1
+ import { t as readManifest } from "../../manifest-BIKVDJML.js";
2
+ import { n as renderTemplate, t as writeFiles } from "../../write-CSwG4Stj.js";
3
+ import { t as detectProject } from "../../detect-AOq1ehTE.js";
4
+ import { command } from "maltty";
5
+ import { join } from "node:path";
6
+ //#region src/commands/add/config.ts
7
+ const addConfigCommand = command({
8
+ description: "Add a config schema to your project",
9
+ handler: async (ctx) => {
10
+ const [detectError, project] = await detectProject(process.cwd());
11
+ if (detectError) return ctx.fail(detectError.message);
12
+ if (!project) return ctx.fail("Not in a maltty project. Run `maltty init` first.");
13
+ const projectName = await resolveProjectName(project.rootDir);
14
+ ctx.status.spinner.start("Generating config...");
15
+ const [renderError, rendered] = await renderTemplate({
16
+ templateDir: join(import.meta.dirname, "..", "..", "lib", "templates", "config"),
17
+ variables: { name: projectName }
18
+ });
19
+ if (renderError) {
20
+ ctx.status.spinner.stop("Failed");
21
+ return ctx.fail(renderError.message);
22
+ }
23
+ const [writeError, result] = await writeFiles({
24
+ files: rendered,
25
+ outputDir: join(project.rootDir, "src"),
26
+ overwrite: false
27
+ });
28
+ if (writeError) {
29
+ ctx.status.spinner.stop("Failed");
30
+ return ctx.fail(writeError.message);
31
+ }
32
+ ctx.status.spinner.stop("Config created!");
33
+ const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
34
+ if (summary.length > 0) ctx.log.raw(summary);
35
+ ctx.log.newline();
36
+ ctx.log.raw("Next steps:");
37
+ ctx.log.raw(" 1. Add fields to the config schema in src/config.ts");
38
+ ctx.log.raw(" 2. Import and pass the schema to cli({ config: { schema: configSchema } })");
39
+ }
40
+ });
41
+ const DEFAULT_NAME = "my-app";
42
+ /**
43
+ * Resolve the project name from the project's package.json.
44
+ *
45
+ * @param rootDir - The project root directory.
46
+ * @returns The project name from package.json, or a default fallback.
47
+ * @private
48
+ */
49
+ async function resolveProjectName(rootDir) {
50
+ const [error, manifest] = await readManifest(rootDir);
51
+ if (error || !manifest.name) return DEFAULT_NAME;
52
+ return manifest.name;
53
+ }
54
+ //#endregion
55
+ export { addConfigCommand as default };
56
+
57
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","names":[],"sources":["../../../src/commands/add/config.ts"],"sourcesContent":["import { join } from 'node:path'\n\nimport { readManifest } from '@maltty/utils/manifest'\nimport { command } from 'maltty'\nimport type { Command, CommandContext } from 'maltty'\n\nimport { detectProject } from '../../lib/detect.js'\nimport { renderTemplate } from '../../lib/render.js'\nimport { writeFiles } from '../../lib/write.js'\n\nconst addConfigCommand: Command = command({\n description: 'Add a config schema to your project',\n handler: async (ctx: CommandContext) => {\n const cwd = process.cwd()\n\n const [detectError, project] = await detectProject(cwd)\n if (detectError) {\n return ctx.fail(detectError.message)\n }\n if (!project) {\n return ctx.fail('Not in a maltty project. Run `maltty init` first.')\n }\n\n const projectName = await resolveProjectName(project.rootDir)\n\n ctx.status.spinner.start('Generating config...')\n\n const templateDir = join(import.meta.dirname, '..', '..', 'lib', 'templates', 'config')\n const [renderError, rendered] = await renderTemplate({\n templateDir,\n variables: { name: projectName },\n })\n\n if (renderError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(renderError.message)\n }\n\n const outputDir = join(project.rootDir, 'src')\n const [writeError, result] = await writeFiles({ files: rendered, outputDir, overwrite: false })\n\n if (writeError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(writeError.message)\n }\n\n ctx.status.spinner.stop('Config created!')\n\n const lines = [\n ...result.written.map((file) => ` created ${file}`),\n ...result.skipped.map((file) => ` skipped ${file} (already exists)`),\n ]\n const summary = lines.join('\\n')\n if (summary.length > 0) {\n ctx.log.raw(summary)\n }\n\n ctx.log.newline()\n ctx.log.raw('Next steps:')\n ctx.log.raw(' 1. Add fields to the config schema in src/config.ts')\n ctx.log.raw(' 2. Import and pass the schema to cli({ config: { schema: configSchema } })')\n },\n})\n\nexport default addConfigCommand\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_NAME = 'my-app'\n\n/**\n * Resolve the project name from the project's package.json.\n *\n * @param rootDir - The project root directory.\n * @returns The project name from package.json, or a default fallback.\n * @private\n */\nasync function resolveProjectName(rootDir: string): Promise<string> {\n const [error, manifest] = await readManifest(rootDir)\n if (error || !manifest.name) {\n return DEFAULT_NAME\n }\n return manifest.name\n}\n"],"mappings":";;;;;;AAUA,MAAM,mBAA4B,QAAQ;CACxC,aAAa;CACb,SAAS,OAAO,QAAwB;EAGtC,MAAM,CAAC,aAAa,WAAW,MAAM,cAFzB,QAAQ,KAAK,CAE8B;AACvD,MAAI,YACF,QAAO,IAAI,KAAK,YAAY,QAAQ;AAEtC,MAAI,CAAC,QACH,QAAO,IAAI,KAAK,oDAAoD;EAGtE,MAAM,cAAc,MAAM,mBAAmB,QAAQ,QAAQ;AAE7D,MAAI,OAAO,QAAQ,MAAM,uBAAuB;EAGhD,MAAM,CAAC,aAAa,YAAY,MAAM,eAAe;GACnD,aAFkB,KAAK,OAAO,KAAK,SAAS,MAAM,MAAM,OAAO,aAAa,SAAS;GAGrF,WAAW,EAAE,MAAM,aAAa;GACjC,CAAC;AAEF,MAAI,aAAa;AACf,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,YAAY,QAAQ;;EAItC,MAAM,CAAC,YAAY,UAAU,MAAM,WAAW;GAAE,OAAO;GAAU,WAD/C,KAAK,QAAQ,SAAS,MAAM;GAC8B,WAAW;GAAO,CAAC;AAE/F,MAAI,YAAY;AACd,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,WAAW,QAAQ;;AAGrC,MAAI,OAAO,QAAQ,KAAK,kBAAkB;EAM1C,MAAM,UAJQ,CACZ,GAAG,OAAO,QAAQ,KAAK,SAAS,aAAa,OAAO,EACpD,GAAG,OAAO,QAAQ,KAAK,SAAS,aAAa,KAAK,mBAAmB,CACtE,CACqB,KAAK,KAAK;AAChC,MAAI,QAAQ,SAAS,EACnB,KAAI,IAAI,IAAI,QAAQ;AAGtB,MAAI,IAAI,SAAS;AACjB,MAAI,IAAI,IAAI,cAAc;AAC1B,MAAI,IAAI,IAAI,wDAAwD;AACpE,MAAI,IAAI,IAAI,+EAA+E;;CAE9F,CAAC;AAQF,MAAM,eAAe;;;;;;;;AASrB,eAAe,mBAAmB,SAAkC;CAClE,MAAM,CAAC,OAAO,YAAY,MAAM,aAAa,QAAQ;AACrD,KAAI,SAAS,CAAC,SAAS,KACrB,QAAO;AAET,QAAO,SAAS"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "maltty";
2
+
3
+ //#region src/commands/add/index.d.ts
4
+ declare const addCommand: Command;
5
+ //#endregion
6
+ export { addCommand as default };
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/commands/add/index.ts"],"mappings":";;;cAGM,UAAA,EAAY,OAAA"}
@@ -0,0 +1,7 @@
1
+ import { command } from "maltty";
2
+ //#region src/commands/add/index.ts
3
+ const addCommand = command({ description: "Add a command, middleware, or config to your project" });
4
+ //#endregion
5
+ export { addCommand as default };
6
+
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/commands/add/index.ts"],"sourcesContent":["import { command } from 'maltty'\nimport type { Command } from 'maltty'\n\nconst addCommand: Command = command({\n description: 'Add a command, middleware, or config to your project',\n})\n\nexport default addCommand\n"],"mappings":";;AAGA,MAAM,aAAsB,QAAQ,EAClC,aAAa,wDACd,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "maltty";
2
+
3
+ //#region src/commands/add/middleware.d.ts
4
+ declare const addMiddlewareCommand: Command;
5
+ //#endregion
6
+ export { addMiddlewareCommand as default };
7
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","names":[],"sources":["../../../src/commands/add/middleware.ts"],"mappings":";;;cAkBM,oBAAA,EAAsB,OAAA"}
@@ -0,0 +1,88 @@
1
+ import { n as renderTemplate, t as writeFiles } from "../../write-CSwG4Stj.js";
2
+ import { t as isKebabCase } from "../../validate-C_SXBoLq.js";
3
+ import { t as detectProject } from "../../detect-AOq1ehTE.js";
4
+ import { command } from "maltty";
5
+ import { join } from "node:path";
6
+ import { z } from "zod";
7
+ //#region src/commands/add/middleware.ts
8
+ const addMiddlewareCommand = command({
9
+ options: z.object({
10
+ description: z.string().describe("Middleware description").optional(),
11
+ name: z.string().describe("Middleware name (kebab-case)").optional()
12
+ }),
13
+ description: "Add a new middleware to your project",
14
+ handler: async (ctx) => {
15
+ const [detectError, project] = await detectProject(process.cwd());
16
+ if (detectError) return ctx.fail(detectError.message);
17
+ if (!project) return ctx.fail("Not in a maltty project. Run `maltty init` first.");
18
+ const middlewareName = await resolveMiddlewareName(ctx);
19
+ const middlewareDescription = await resolveDescription(ctx);
20
+ ctx.status.spinner.start("Generating middleware...");
21
+ const [renderError, rendered] = await renderTemplate({
22
+ templateDir: join(import.meta.dirname, "..", "..", "lib", "templates", "middleware"),
23
+ variables: {
24
+ description: middlewareDescription,
25
+ middlewareName
26
+ }
27
+ });
28
+ if (renderError) {
29
+ ctx.status.spinner.stop("Failed");
30
+ return ctx.fail(renderError.message);
31
+ }
32
+ const outputDir = join(project.rootDir, "src", "middleware");
33
+ const [writeError, result] = await writeFiles({
34
+ files: rendered.map((file) => ({
35
+ content: file.content,
36
+ relativePath: file.relativePath.replace("middleware.ts", `${middlewareName}.ts`)
37
+ })),
38
+ outputDir,
39
+ overwrite: false
40
+ });
41
+ if (writeError) {
42
+ ctx.status.spinner.stop("Failed");
43
+ return ctx.fail(writeError.message);
44
+ }
45
+ ctx.status.spinner.stop("Middleware created!");
46
+ const summary = [...result.written.map((file) => ` created ${file}`), ...result.skipped.map((file) => ` skipped ${file} (already exists)`)].join("\n");
47
+ if (summary.length > 0) ctx.log.raw(summary);
48
+ }
49
+ });
50
+ /**
51
+ * Resolve the middleware name from args or prompt.
52
+ *
53
+ * @param ctx - Command context.
54
+ * @returns The validated middleware name.
55
+ * @private
56
+ */
57
+ async function resolveMiddlewareName(ctx) {
58
+ if (ctx.args.name) {
59
+ if (!isKebabCase(ctx.args.name)) return ctx.fail("Middleware name must be kebab-case (e.g. auth)");
60
+ return ctx.args.name;
61
+ }
62
+ return ctx.prompts.text({
63
+ message: "Middleware name",
64
+ placeholder: "auth",
65
+ validate: (value) => {
66
+ if (value === void 0 || !isKebabCase(value)) return "Must be kebab-case (e.g. auth)";
67
+ }
68
+ });
69
+ }
70
+ /**
71
+ * Resolve the middleware description from args or prompt.
72
+ *
73
+ * @param ctx - Command context.
74
+ * @returns The middleware description string.
75
+ * @private
76
+ */
77
+ async function resolveDescription(ctx) {
78
+ if (ctx.args.description) return ctx.args.description;
79
+ return ctx.prompts.text({
80
+ defaultValue: "",
81
+ message: "Description",
82
+ placeholder: "What does this middleware do?"
83
+ });
84
+ }
85
+ //#endregion
86
+ export { addMiddlewareCommand as default };
87
+
88
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","names":[],"sources":["../../../src/commands/add/middleware.ts"],"sourcesContent":["import { join } from 'node:path'\n\nimport { command } from 'maltty'\nimport type { Command, CommandContext } from 'maltty'\nimport { z } from 'zod'\n\nimport { detectProject } from '../../lib/detect.js'\nimport { renderTemplate } from '../../lib/render.js'\nimport { isKebabCase } from '../../lib/validate.js'\nimport { writeFiles } from '../../lib/write.js'\n\nconst options = z.object({\n description: z.string().describe('Middleware description').optional(),\n name: z.string().describe('Middleware name (kebab-case)').optional(),\n})\n\ntype AddMiddlewareArgs = z.infer<typeof options>\n\nconst addMiddlewareCommand: Command = command({\n options,\n description: 'Add a new middleware to your project',\n handler: async (ctx: CommandContext<AddMiddlewareArgs>) => {\n const [detectError, project] = await detectProject(process.cwd())\n if (detectError) {\n return ctx.fail(detectError.message)\n }\n if (!project) {\n return ctx.fail('Not in a maltty project. Run `maltty init` first.')\n }\n\n const middlewareName = await resolveMiddlewareName(ctx)\n const middlewareDescription = await resolveDescription(ctx)\n\n ctx.status.spinner.start('Generating middleware...')\n\n const templateDir = join(import.meta.dirname, '..', '..', 'lib', 'templates', 'middleware')\n const [renderError, rendered] = await renderTemplate({\n templateDir,\n variables: { description: middlewareDescription, middlewareName },\n })\n\n if (renderError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(renderError.message)\n }\n\n const outputDir = join(project.rootDir, 'src', 'middleware')\n const files = rendered.map((file) => ({\n content: file.content,\n relativePath: file.relativePath.replace('middleware.ts', `${middlewareName}.ts`),\n }))\n\n const [writeError, result] = await writeFiles({ files, outputDir, overwrite: false })\n\n if (writeError) {\n ctx.status.spinner.stop('Failed')\n return ctx.fail(writeError.message)\n }\n\n ctx.status.spinner.stop('Middleware created!')\n\n const lines = [\n ...result.written.map((file) => ` created ${file}`),\n ...result.skipped.map((file) => ` skipped ${file} (already exists)`),\n ]\n const summary = lines.join('\\n')\n if (summary.length > 0) {\n ctx.log.raw(summary)\n }\n },\n})\n\nexport default addMiddlewareCommand\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the middleware name from args or prompt.\n *\n * @param ctx - Command context.\n * @returns The validated middleware name.\n * @private\n */\nasync function resolveMiddlewareName(ctx: CommandContext<AddMiddlewareArgs>): Promise<string> {\n if (ctx.args.name) {\n if (!isKebabCase(ctx.args.name)) {\n return ctx.fail('Middleware name must be kebab-case (e.g. auth)')\n }\n return ctx.args.name\n }\n return ctx.prompts.text({\n message: 'Middleware name',\n placeholder: 'auth',\n validate: (value: string | undefined) => {\n if (value === undefined || !isKebabCase(value)) {\n return 'Must be kebab-case (e.g. auth)'\n }\n return undefined\n },\n })\n}\n\n/**\n * Resolve the middleware description from args or prompt.\n *\n * @param ctx - Command context.\n * @returns The middleware description string.\n * @private\n */\nasync function resolveDescription(ctx: CommandContext<AddMiddlewareArgs>): Promise<string> {\n if (ctx.args.description) {\n return ctx.args.description\n }\n return ctx.prompts.text({\n defaultValue: '',\n message: 'Description',\n placeholder: 'What does this middleware do?',\n })\n}\n"],"mappings":";;;;;;;AAkBA,MAAM,uBAAgC,QAAQ;CAC5C,SARc,EAAE,OAAO;EACvB,aAAa,EAAE,QAAQ,CAAC,SAAS,yBAAyB,CAAC,UAAU;EACrE,MAAM,EAAE,QAAQ,CAAC,SAAS,+BAA+B,CAAC,UAAU;EACrE,CAAC;CAMA,aAAa;CACb,SAAS,OAAO,QAA2C;EACzD,MAAM,CAAC,aAAa,WAAW,MAAM,cAAc,QAAQ,KAAK,CAAC;AACjE,MAAI,YACF,QAAO,IAAI,KAAK,YAAY,QAAQ;AAEtC,MAAI,CAAC,QACH,QAAO,IAAI,KAAK,oDAAoD;EAGtE,MAAM,iBAAiB,MAAM,sBAAsB,IAAI;EACvD,MAAM,wBAAwB,MAAM,mBAAmB,IAAI;AAE3D,MAAI,OAAO,QAAQ,MAAM,2BAA2B;EAGpD,MAAM,CAAC,aAAa,YAAY,MAAM,eAAe;GACnD,aAFkB,KAAK,OAAO,KAAK,SAAS,MAAM,MAAM,OAAO,aAAa,aAAa;GAGzF,WAAW;IAAE,aAAa;IAAuB;IAAgB;GAClE,CAAC;AAEF,MAAI,aAAa;AACf,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,YAAY,QAAQ;;EAGtC,MAAM,YAAY,KAAK,QAAQ,SAAS,OAAO,aAAa;EAM5D,MAAM,CAAC,YAAY,UAAU,MAAM,WAAW;GAAE,OALlC,SAAS,KAAK,UAAU;IACpC,SAAS,KAAK;IACd,cAAc,KAAK,aAAa,QAAQ,iBAAiB,GAAG,eAAe,KAAK;IACjF,EAAE;GAEoD;GAAW,WAAW;GAAO,CAAC;AAErF,MAAI,YAAY;AACd,OAAI,OAAO,QAAQ,KAAK,SAAS;AACjC,UAAO,IAAI,KAAK,WAAW,QAAQ;;AAGrC,MAAI,OAAO,QAAQ,KAAK,sBAAsB;EAM9C,MAAM,UAJQ,CACZ,GAAG,OAAO,QAAQ,KAAK,SAAS,aAAa,OAAO,EACpD,GAAG,OAAO,QAAQ,KAAK,SAAS,aAAa,KAAK,mBAAmB,CACtE,CACqB,KAAK,KAAK;AAChC,MAAI,QAAQ,SAAS,EACnB,KAAI,IAAI,IAAI,QAAQ;;CAGzB,CAAC;;;;;;;;AAeF,eAAe,sBAAsB,KAAyD;AAC5F,KAAI,IAAI,KAAK,MAAM;AACjB,MAAI,CAAC,YAAY,IAAI,KAAK,KAAK,CAC7B,QAAO,IAAI,KAAK,iDAAiD;AAEnE,SAAO,IAAI,KAAK;;AAElB,QAAO,IAAI,QAAQ,KAAK;EACtB,SAAS;EACT,aAAa;EACb,WAAW,UAA8B;AACvC,OAAI,UAAU,KAAA,KAAa,CAAC,YAAY,MAAM,CAC5C,QAAO;;EAIZ,CAAC;;;;;;;;;AAUJ,eAAe,mBAAmB,KAAyD;AACzF,KAAI,IAAI,KAAK,YACX,QAAO,IAAI,KAAK;AAElB,QAAO,IAAI,QAAQ,KAAK;EACtB,cAAc;EACd,SAAS;EACT,aAAa;EACd,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { Command } from "maltty";
2
+
3
+ //#region src/commands/build.d.ts
4
+ /**
5
+ * Build a maltty CLI project for production.
6
+ *
7
+ * Loads the project's `maltty.config.ts`, invokes the bundler, and reports
8
+ * the output entry file and directory on success. When `--compile` or
9
+ * `--targets` is provided (or `compile` is set in config), also compiles
10
+ * to standalone binaries via Bun.
11
+ */
12
+ declare const buildCommand: Command;
13
+ //#endregion
14
+ export { buildCommand as default };
15
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","names":[],"sources":["../../src/commands/build.ts"],"mappings":";;;;;AAO6C;;;;;;cA0BvC,YAAA,EAAc,OAAA"}