@tailor-platform/erp-kit 0.2.2 → 0.3.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 (45) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +158 -62
  3. package/dist/cli.mjs +344 -215
  4. package/package.json +3 -2
  5. package/skills/erp-kit-app-1-requirements/SKILL.md +19 -8
  6. package/skills/erp-kit-app-2-requirements-review/SKILL.md +5 -4
  7. package/skills/erp-kit-app-2-requirements-review/references/best-practices-check.md +6 -1
  8. package/skills/erp-kit-app-2-requirements-review/references/boundary-consistency-check.md +6 -1
  9. package/skills/erp-kit-app-3-plan/SKILL.md +4 -7
  10. package/skills/erp-kit-app-3-plan/references/resolver-extraction.md +1 -19
  11. package/skills/erp-kit-app-4-plan-review/SKILL.md +1 -10
  12. package/skills/erp-kit-app-5-impl-backend/SKILL.md +1 -8
  13. package/skills/erp-kit-app-shared/SKILL.md +15 -0
  14. package/skills/erp-kit-app-shared/references/link-format-reference.md +13 -0
  15. package/skills/erp-kit-app-shared/references/naming-conventions.md +21 -0
  16. package/skills/erp-kit-app-shared/references/resolver-classification.md +23 -0
  17. package/skills/erp-kit-app-shared/references/schema-constraints.md +25 -0
  18. package/skills/erp-kit-module-1-requirements/SKILL.md +1 -1
  19. package/skills/erp-kit-module-1-requirements/references/feature-doc.md +1 -1
  20. package/skills/erp-kit-module-3-plan/SKILL.md +5 -5
  21. package/skills/erp-kit-module-3-plan/references/naming.md +15 -1
  22. package/skills/erp-kit-module-5-impl/SKILL.md +12 -10
  23. package/skills/erp-kit-module-5-impl/references/generated-code.md +2 -2
  24. package/skills/erp-kit-module-6-impl-review/SKILL.md +1 -1
  25. package/skills/erp-kit-module-6-impl-review/references/error-implementation-parity.md +1 -1
  26. package/skills/erp-kit-module-6-impl-review/references/errors.md +1 -1
  27. package/skills/erp-kit-module-shared/references/errors.md +1 -1
  28. package/skills/erp-kit-module-shared/references/queries.md +1 -1
  29. package/skills/erp-kit-module-shared/references/structure.md +1 -1
  30. package/skills/erp-kit-update/SKILL.md +2 -2
  31. package/src/commands/app/index.ts +57 -24
  32. package/src/commands/generate-doc.test.ts +63 -0
  33. package/src/commands/generate-doc.ts +98 -0
  34. package/src/commands/init-module.test.ts +43 -0
  35. package/src/commands/init-module.ts +74 -0
  36. package/src/commands/module/generate.ts +33 -13
  37. package/src/commands/module/index.ts +18 -28
  38. package/src/{commands/scaffold.test.ts → generator/generate-code-boilerplate.test.ts} +19 -89
  39. package/src/generator/generate-code.test.ts +24 -0
  40. package/src/generator/generate-code.ts +101 -4
  41. package/src/integration.test.ts +2 -2
  42. package/templates/scaffold/app/backend/package.json +4 -4
  43. package/templates/scaffold/app/frontend/package.json +10 -10
  44. package/templates/workflows/erp-kit-check.yml +2 -2
  45. package/src/commands/scaffold.ts +0 -176
@@ -1,14 +1,17 @@
1
+ import path from "node:path";
1
2
  import { z } from "zod";
2
3
  import { defineCommand, arg } from "politty";
3
4
  import { runCheck } from "../check";
4
5
  import { runSyncCheck, formatSyncCheckReport } from "../sync-check";
5
- import { runScaffold, APP_TYPES, type ScaffoldType } from "../scaffold";
6
+ import { runGenerateDoc, APP_DOC_TYPES, type DocType } from "../generate-doc";
7
+ import { runGenerateAppCode } from "../../generator/generate-code";
8
+ import { runInitAppWithReadme } from "../init-module";
6
9
 
7
10
  const cwd = process.cwd();
8
11
 
9
- const rootArgs = z.object({
10
- root: arg(z.string(), {
11
- alias: "r",
12
+ const pathArgs = z.object({
13
+ path: arg(z.string(), {
14
+ alias: "p",
12
15
  description: "Path to app-compose directory",
13
16
  }),
14
17
  });
@@ -16,9 +19,9 @@ const rootArgs = z.object({
16
19
  const checkCommand = defineCommand({
17
20
  name: "check",
18
21
  description: "Validate app docs against schemas",
19
- args: rootArgs,
22
+ args: pathArgs,
20
23
  run: async (args) => {
21
- const exitCode = await runCheck({ appRoot: args.root }, cwd);
24
+ const exitCode = await runCheck({ appRoot: args.path }, cwd);
22
25
  process.exit(exitCode);
23
26
  },
24
27
  });
@@ -26,25 +29,40 @@ const checkCommand = defineCommand({
26
29
  const syncCheckCommand = defineCommand({
27
30
  name: "sync-check",
28
31
  description: "Validate source <-> doc correspondence",
29
- args: rootArgs,
32
+ args: pathArgs,
30
33
  run: async (args) => {
31
- const result = await runSyncCheck({ appRoot: args.root }, cwd);
34
+ const result = await runSyncCheck({ appRoot: args.path }, cwd);
32
35
  console.log(formatSyncCheckReport(result));
33
36
  process.exit(result.exitCode);
34
37
  },
35
38
  });
36
39
 
37
- const scaffoldCommand = defineCommand({
38
- name: "scaffold",
39
- description: "Generate app doc from schema template",
40
- args: rootArgs.extend({
41
- type: arg(z.enum(APP_TYPES as unknown as [string, ...string[]]), {
40
+ const initCommand = defineCommand({
41
+ name: "init",
42
+ description: "Bootstrap a new app with directory structure and README",
43
+ args: z.object({
44
+ name: arg(z.string(), {
42
45
  positional: true,
43
- description: `Scaffold type (${APP_TYPES.join(", ")})`,
46
+ description: "App name",
44
47
  }),
45
- parent: arg(z.string(), {
48
+ dir: arg(z.string(), {
46
49
  positional: true,
47
- description: "App name",
50
+ description: "Parent directory where the app will be created",
51
+ }),
52
+ }),
53
+ run: async (args) => {
54
+ const exitCode = await runInitAppWithReadme(args.name, args.dir, cwd);
55
+ process.exit(exitCode);
56
+ },
57
+ });
58
+
59
+ const docCommand = defineCommand({
60
+ name: "doc",
61
+ description: "Create a documentation file from a schema template",
62
+ args: pathArgs.extend({
63
+ type: arg(z.enum(APP_DOC_TYPES as unknown as [string, ...string[]]), {
64
+ positional: true,
65
+ description: `Doc type (${APP_DOC_TYPES.join(", ")})`,
48
66
  }),
49
67
  name: arg(z.string().optional(), {
50
68
  positional: true,
@@ -52,23 +70,38 @@ const scaffoldCommand = defineCommand({
52
70
  }),
53
71
  }),
54
72
  run: async (args) => {
55
- const exitCode = await runScaffold(
56
- args.type as ScaffoldType,
57
- args.parent,
58
- args.name,
59
- args.root,
60
- cwd,
61
- );
73
+ const exitCode = await runGenerateDoc(args.type as DocType, args.name, args.path, cwd);
74
+ process.exit(exitCode);
75
+ },
76
+ });
77
+
78
+ const codeCommand = defineCommand({
79
+ name: "code",
80
+ description: "Generate boilerplate source files from docs",
81
+ args: pathArgs,
82
+ run: (args) => {
83
+ const appPath = path.resolve(cwd, args.path);
84
+ const exitCode = runGenerateAppCode(appPath);
62
85
  process.exit(exitCode);
63
86
  },
64
87
  });
65
88
 
89
+ const generateCommand = defineCommand({
90
+ name: "generate",
91
+ description: "Generate docs and code for an app",
92
+ subCommands: {
93
+ doc: docCommand,
94
+ code: codeCommand,
95
+ },
96
+ });
97
+
66
98
  export const appCommand = defineCommand({
67
99
  name: "app",
68
100
  description: "App-compose management",
69
101
  subCommands: {
70
102
  check: checkCommand,
71
103
  "sync-check": syncCheckCommand,
72
- scaffold: scaffoldCommand,
104
+ init: initCommand,
105
+ generate: generateCommand,
73
106
  },
74
107
  });
@@ -0,0 +1,63 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { resolveDocPath } from "./generate-doc";
3
+
4
+ describe("resolveDocPath", () => {
5
+ it("resolves command doc path", () => {
6
+ const result = resolveDocPath("command", "CreateOrder", "modules/inventory");
7
+ expect(result).toBe("modules/inventory/docs/commands/CreateOrder.md");
8
+ });
9
+
10
+ it("resolves feature doc path", () => {
11
+ const result = resolveDocPath("feature", "stock-tracking", "modules/inventory");
12
+ expect(result).toBe("modules/inventory/docs/features/stock-tracking.md");
13
+ });
14
+
15
+ it("resolves model doc path", () => {
16
+ const result = resolveDocPath("model", "StockItem", "modules/inventory");
17
+ expect(result).toBe("modules/inventory/docs/models/StockItem.md");
18
+ });
19
+
20
+ it("resolves query doc path", () => {
21
+ const result = resolveDocPath("query", "ConvertQuantity", "modules/inventory");
22
+ expect(result).toBe("modules/inventory/docs/queries/ConvertQuantity.md");
23
+ });
24
+
25
+ it("resolves actors doc path", () => {
26
+ const result = resolveDocPath("actors", "admin", "examples/my-app");
27
+ expect(result).toBe("examples/my-app/docs/actors/admin.md");
28
+ });
29
+
30
+ it("resolves business-flow doc path", () => {
31
+ const result = resolveDocPath("business-flow", "onboarding", "examples/my-app");
32
+ expect(result).toBe("examples/my-app/docs/business-flow/onboarding/README.md");
33
+ });
34
+
35
+ it("resolves story doc path with flow/name format", () => {
36
+ const result = resolveDocPath("story", "onboarding/admin--create-user", "examples/my-app");
37
+ expect(result).toBe(
38
+ "examples/my-app/docs/business-flow/onboarding/story/admin--create-user.md",
39
+ );
40
+ });
41
+
42
+ it("resolves screen doc path", () => {
43
+ const result = resolveDocPath("screen", "supplier-list", "examples/my-app");
44
+ expect(result).toBe("examples/my-app/docs/screen/supplier-list.md");
45
+ });
46
+
47
+ it("resolves resolver doc path", () => {
48
+ const result = resolveDocPath("resolver", "create-supplier", "examples/my-app");
49
+ expect(result).toBe("examples/my-app/docs/resolver/create-supplier.md");
50
+ });
51
+
52
+ it("throws when name is missing", () => {
53
+ expect(() => resolveDocPath("command", undefined, "modules/inventory")).toThrow(
54
+ "Name is required",
55
+ );
56
+ });
57
+
58
+ it("throws when story name is not flow/name format", () => {
59
+ expect(() => resolveDocPath("story", "bad-name", "examples/my-app")).toThrow(
60
+ "Story name must be",
61
+ );
62
+ });
63
+ });
@@ -0,0 +1,98 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+ import { runMdschema } from "../mdschema";
4
+ import { ALL_SCHEMAS } from "../schemas";
5
+
6
+ export const MODULE_DOC_TYPES = ["feature", "command", "model", "query"] as const;
7
+ export const APP_DOC_TYPES = ["actors", "business-flow", "story", "screen", "resolver"] as const;
8
+ export const ALL_DOC_TYPES = [...MODULE_DOC_TYPES, ...APP_DOC_TYPES] as const;
9
+
10
+ export type DocType = (typeof ALL_DOC_TYPES)[number];
11
+
12
+ const MODULE_DIR_MAP: Record<string, string> = {
13
+ feature: "docs/features",
14
+ command: "docs/commands",
15
+ model: "docs/models",
16
+ query: "docs/queries",
17
+ };
18
+
19
+ const APP_DIR_MAP: Record<string, string> = {
20
+ actors: "docs/actors",
21
+ "business-flow": "docs/business-flow",
22
+ screen: "docs/screen",
23
+ resolver: "docs/resolver",
24
+ };
25
+
26
+ export function resolveDocPath(
27
+ type: DocType,
28
+ name: string | undefined,
29
+ modulePath: string,
30
+ ): string {
31
+ if (!name) {
32
+ throw new Error(`Name is required for doc type "${type}"`);
33
+ }
34
+
35
+ if (type === "business-flow") {
36
+ return path.join(modulePath, "docs/business-flow", name, "README.md");
37
+ }
38
+
39
+ if (type === "story") {
40
+ const parts = name.split("/");
41
+ if (parts.length !== 2) {
42
+ throw new Error(
43
+ `Story name must be "<flow>/<story>" (e.g., "onboarding/admin--create-user")`,
44
+ );
45
+ }
46
+ return path.join(modulePath, "docs/business-flow", parts[0], "story", `${parts[1]}.md`);
47
+ }
48
+
49
+ if (MODULE_DIR_MAP[type]) {
50
+ return path.join(modulePath, MODULE_DIR_MAP[type], `${name}.md`);
51
+ }
52
+
53
+ if (APP_DIR_MAP[type]) {
54
+ return path.join(modulePath, APP_DIR_MAP[type], `${name}.md`);
55
+ }
56
+
57
+ throw new Error(`Unknown doc type: ${type}`);
58
+ }
59
+
60
+ export async function runGenerateDoc(
61
+ type: DocType,
62
+ name: string | undefined,
63
+ modulePath: string,
64
+ cwd: string,
65
+ ): Promise<number> {
66
+ const outputPath = resolveDocPath(type, name, modulePath);
67
+ const absoluteOutput = path.resolve(cwd, outputPath);
68
+
69
+ if (fs.existsSync(absoluteOutput)) {
70
+ console.error(`File already exists: ${outputPath}`);
71
+ return 1;
72
+ }
73
+
74
+ const schemaPath = ALL_SCHEMAS[type];
75
+ if (!schemaPath) {
76
+ console.error(`No schema found for type: ${type}`);
77
+ return 2;
78
+ }
79
+
80
+ try {
81
+ fs.mkdirSync(path.dirname(absoluteOutput), { recursive: true });
82
+ } catch (err) {
83
+ console.error(
84
+ `Failed to create directory: ${err instanceof Error ? err.message : String(err)}`,
85
+ );
86
+ return 1;
87
+ }
88
+
89
+ const { exitCode, stdout, stderr } = await runMdschema(
90
+ ["generate", "--schema", schemaPath, "--output", absoluteOutput],
91
+ cwd,
92
+ );
93
+
94
+ if (stdout.trim()) console.log(stdout);
95
+ if (stderr.trim()) console.error(stderr);
96
+
97
+ return exitCode;
98
+ }
@@ -0,0 +1,43 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { describe, it, expect, afterEach } from "vitest";
5
+ import { runInitModule, runInitApp } from "./init-module";
6
+
7
+ describe("runInitModule", () => {
8
+ let tmpDir: string;
9
+
10
+ afterEach(() => {
11
+ if (tmpDir) {
12
+ fs.rmSync(tmpDir, { recursive: true, force: true });
13
+ }
14
+ });
15
+
16
+ it("creates module directory", () => {
17
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-module-test-"));
18
+ const moduleDir = path.join(tmpDir, "my-module");
19
+ fs.mkdirSync(moduleDir, { recursive: true });
20
+
21
+ const exitCode = runInitModule("my-module", tmpDir);
22
+ expect(exitCode).toBe(1); // should fail — dir exists
23
+ });
24
+ });
25
+
26
+ describe("runInitApp", () => {
27
+ let tmpDir: string;
28
+
29
+ afterEach(() => {
30
+ if (tmpDir) {
31
+ fs.rmSync(tmpDir, { recursive: true, force: true });
32
+ }
33
+ });
34
+
35
+ it("errors if app directory already exists", () => {
36
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "init-app-test-"));
37
+ const appDir = path.join(tmpDir, "my-app");
38
+ fs.mkdirSync(appDir, { recursive: true });
39
+
40
+ const exitCode = runInitApp("my-app", tmpDir);
41
+ expect(exitCode).toBe(1);
42
+ });
43
+ });
@@ -0,0 +1,74 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs";
3
+ import { runMdschema } from "../mdschema";
4
+ import { MODULE_SCHEMAS, APP_COMPOSE_SCHEMAS } from "../schemas";
5
+
6
+ export function runInitModule(name: string, dir: string): number {
7
+ const moduleDir = path.resolve(dir, name);
8
+
9
+ if (fs.existsSync(moduleDir)) {
10
+ console.error(`Directory already exists: ${moduleDir}`);
11
+ return 1;
12
+ }
13
+
14
+ fs.mkdirSync(moduleDir, { recursive: true });
15
+ return 0;
16
+ }
17
+
18
+ export async function runInitModuleWithReadme(
19
+ name: string,
20
+ dir: string,
21
+ cwd: string,
22
+ ): Promise<number> {
23
+ const initResult = runInitModule(name, dir);
24
+ if (initResult !== 0) return initResult;
25
+
26
+ const moduleDir = path.resolve(cwd, dir, name);
27
+ const readmePath = path.join(moduleDir, "README.md");
28
+ const schemaPath = MODULE_SCHEMAS.module;
29
+
30
+ const { exitCode, stdout, stderr } = await runMdschema(
31
+ ["generate", "--schema", schemaPath, "--output", readmePath],
32
+ cwd,
33
+ );
34
+
35
+ if (stdout.trim()) console.log(stdout);
36
+ if (stderr.trim()) console.error(stderr);
37
+
38
+ return exitCode;
39
+ }
40
+
41
+ export function runInitApp(name: string, dir: string): number {
42
+ const appDir = path.resolve(dir, name);
43
+
44
+ if (fs.existsSync(appDir)) {
45
+ console.error(`Directory already exists: ${appDir}`);
46
+ return 1;
47
+ }
48
+
49
+ fs.mkdirSync(appDir, { recursive: true });
50
+ return 0;
51
+ }
52
+
53
+ export async function runInitAppWithReadme(
54
+ name: string,
55
+ dir: string,
56
+ cwd: string,
57
+ ): Promise<number> {
58
+ const initResult = runInitApp(name, dir);
59
+ if (initResult !== 0) return initResult;
60
+
61
+ const appDir = path.resolve(cwd, dir, name);
62
+ const readmePath = path.join(appDir, "README.md");
63
+ const schemaPath = APP_COMPOSE_SCHEMAS.app;
64
+
65
+ const { exitCode, stdout, stderr } = await runMdschema(
66
+ ["generate", "--schema", schemaPath, "--output", readmePath],
67
+ cwd,
68
+ );
69
+
70
+ if (stdout.trim()) console.log(stdout);
71
+ if (stderr.trim()) console.error(stderr);
72
+
73
+ return exitCode;
74
+ }
@@ -2,34 +2,54 @@ import path from "node:path";
2
2
  import { defineCommand, arg } from "politty";
3
3
  import { z } from "zod";
4
4
  import { runGenerateCode } from "../../generator/generate-code";
5
+ import { runGenerateDoc, MODULE_DOC_TYPES, type DocType } from "../generate-doc";
5
6
 
6
7
  const cwd = process.cwd();
7
8
 
8
- const codeCommand = defineCommand({
9
- name: "code",
10
- description: "Generate errors, permissions, command shells, and query shells from docs",
11
- args: z.object({
12
- root: arg(z.string(), {
13
- alias: "r",
14
- description: "Path to modules directory",
9
+ const pathArgs = z.object({
10
+ path: arg(z.string(), {
11
+ alias: "p",
12
+ description: "Path to the module directory",
13
+ }),
14
+ });
15
+
16
+ const docCommand = defineCommand({
17
+ name: "doc",
18
+ description: "Create a documentation file from a schema template",
19
+ args: pathArgs.extend({
20
+ type: arg(z.enum(MODULE_DOC_TYPES as unknown as [string, ...string[]]), {
21
+ positional: true,
22
+ description: `Doc type (${MODULE_DOC_TYPES.join(", ")})`,
15
23
  }),
16
- module: arg(z.string(), {
24
+ name: arg(z.string().optional(), {
17
25
  positional: true,
18
- description: "Module name (e.g., primitives, item-management)",
26
+ description: "Item name (required for all types)",
19
27
  }),
20
28
  }),
29
+ run: async (args) => {
30
+ const exitCode = await runGenerateDoc(args.type as DocType, args.name, args.path, cwd);
31
+ process.exit(exitCode);
32
+ },
33
+ });
34
+
35
+ const codeCommand = defineCommand({
36
+ name: "code",
37
+ description: "Generate boilerplate, implementation stubs, and generated code from docs",
38
+ args: pathArgs,
21
39
  run: (args) => {
22
- const modulePath = path.resolve(cwd, args.root, args.module);
23
- console.log(`Generating code for ${args.module}...`);
24
- const exitCode = runGenerateCode(modulePath, args.module);
40
+ const modulePath = path.resolve(cwd, args.path);
41
+ const moduleName = path.basename(modulePath);
42
+ console.log(`Generating code for ${moduleName}...`);
43
+ const exitCode = runGenerateCode(modulePath, moduleName);
25
44
  process.exit(exitCode);
26
45
  },
27
46
  });
28
47
 
29
48
  export const generateCommand = defineCommand({
30
49
  name: "generate",
31
- description: "Generate code from model definitions and docs",
50
+ description: "Generate docs and code for a module",
32
51
  subCommands: {
52
+ doc: docCommand,
33
53
  code: codeCommand,
34
54
  },
35
55
  });
@@ -1,16 +1,16 @@
1
1
  import { z } from "zod";
2
2
  import { defineCommand, arg } from "politty";
3
3
  import { runCheck } from "../check";
4
+ import { runInitModuleWithReadme } from "../init-module";
4
5
  import { runSyncCheck, formatSyncCheckReport } from "../sync-check";
5
- import { runScaffold, MODULE_TYPES, type ScaffoldType } from "../scaffold";
6
- import { runModuleList } from "./list";
7
6
  import { generateCommand } from "./generate";
7
+ import { runModuleList } from "./list";
8
8
 
9
9
  const cwd = process.cwd();
10
10
 
11
- const rootArgs = z.object({
12
- root: arg(z.string(), {
13
- alias: "r",
11
+ const pathArgs = z.object({
12
+ path: arg(z.string(), {
13
+ alias: "p",
14
14
  description: "Path to modules directory",
15
15
  }),
16
16
  });
@@ -27,9 +27,9 @@ const listCommand = defineCommand({
27
27
  const checkCommand = defineCommand({
28
28
  name: "check",
29
29
  description: "Validate module docs against schemas",
30
- args: rootArgs,
30
+ args: pathArgs,
31
31
  run: async (args) => {
32
- const exitCode = await runCheck({ modulesRoot: args.root }, cwd);
32
+ const exitCode = await runCheck({ modulesRoot: args.path }, cwd);
33
33
  process.exit(exitCode);
34
34
  },
35
35
  });
@@ -37,39 +37,29 @@ const checkCommand = defineCommand({
37
37
  const syncCheckCommand = defineCommand({
38
38
  name: "sync-check",
39
39
  description: "Validate source <-> doc correspondence",
40
- args: rootArgs,
40
+ args: pathArgs,
41
41
  run: async (args) => {
42
- const result = await runSyncCheck({ modulesRoot: args.root }, cwd);
42
+ const result = await runSyncCheck({ modulesRoot: args.path }, cwd);
43
43
  console.log(formatSyncCheckReport(result));
44
44
  process.exit(result.exitCode);
45
45
  },
46
46
  });
47
47
 
48
- const scaffoldCommand = defineCommand({
49
- name: "scaffold",
50
- description: "Generate module doc from schema template",
51
- args: rootArgs.extend({
52
- type: arg(z.enum(MODULE_TYPES as unknown as [string, ...string[]]), {
53
- positional: true,
54
- description: `Scaffold type (${MODULE_TYPES.join(", ")})`,
55
- }),
56
- parent: arg(z.string(), {
48
+ const initCommand = defineCommand({
49
+ name: "init",
50
+ description: "Bootstrap a new module with directory structure and README",
51
+ args: z.object({
52
+ name: arg(z.string(), {
57
53
  positional: true,
58
54
  description: "Module name",
59
55
  }),
60
- name: arg(z.string().optional(), {
56
+ dir: arg(z.string(), {
61
57
  positional: true,
62
- description: "Item name (required for feature, command, model)",
58
+ description: "Parent directory where the module will be created",
63
59
  }),
64
60
  }),
65
61
  run: async (args) => {
66
- const exitCode = await runScaffold(
67
- args.type as ScaffoldType,
68
- args.parent,
69
- args.name,
70
- args.root,
71
- cwd,
72
- );
62
+ const exitCode = await runInitModuleWithReadme(args.name, args.dir, cwd);
73
63
  process.exit(exitCode);
74
64
  },
75
65
  });
@@ -81,7 +71,7 @@ export const moduleCommand = defineCommand({
81
71
  list: listCommand,
82
72
  check: checkCommand,
83
73
  "sync-check": syncCheckCommand,
84
- scaffold: scaffoldCommand,
74
+ init: initCommand,
85
75
  generate: generateCommand,
86
76
  },
87
77
  });