@rawsql-ts/ztd-cli 0.15.0 → 0.17.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 (153) hide show
  1. package/README.md +38 -25
  2. package/dist/commands/init.d.ts +13 -0
  3. package/dist/commands/init.js +372 -118
  4. package/dist/commands/init.js.map +1 -1
  5. package/dist/commands/lint.d.ts +4 -4
  6. package/dist/commands/lint.js +60 -40
  7. package/dist/commands/lint.js.map +1 -1
  8. package/dist/commands/ztdConfig.d.ts +2 -2
  9. package/dist/commands/ztdConfig.js +26 -12
  10. package/dist/commands/ztdConfig.js.map +1 -1
  11. package/dist/utils/optionalDependencies.d.ts +35 -0
  12. package/dist/utils/optionalDependencies.js +96 -0
  13. package/dist/utils/optionalDependencies.js.map +1 -0
  14. package/package.json +18 -10
  15. package/templates/AGENTS.md +36 -296
  16. package/templates/README.md +12 -237
  17. package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.d.ts +38 -0
  18. package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.js +117 -0
  19. package/templates/dist/drivers/pg-testkit/src/driver/PgTestkitClient.js.map +1 -0
  20. package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.d.ts +4 -0
  21. package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.js +71 -0
  22. package/templates/dist/drivers/pg-testkit/src/driver/createPgTestkitPool.js.map +1 -0
  23. package/templates/dist/drivers/pg-testkit/src/index.d.ts +5 -0
  24. package/templates/dist/drivers/pg-testkit/src/index.js +11 -0
  25. package/templates/dist/drivers/pg-testkit/src/index.js.map +1 -0
  26. package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.d.ts +3 -0
  27. package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.js +79 -0
  28. package/templates/dist/drivers/pg-testkit/src/proxy/wrapPgClient.js.map +1 -0
  29. package/templates/dist/drivers/pg-testkit/src/types.d.ts +69 -0
  30. package/templates/dist/drivers/pg-testkit/src/types.js +3 -0
  31. package/templates/dist/drivers/pg-testkit/src/types.js.map +1 -0
  32. package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.d.ts +15 -0
  33. package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.js +34 -0
  34. package/templates/dist/drivers/pg-testkit/src/utils/fixtureState.js.map +1 -0
  35. package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.d.ts +12 -0
  36. package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.js +53 -0
  37. package/templates/dist/drivers/pg-testkit/src/utils/fixtureValidation.js.map +1 -0
  38. package/templates/dist/mapper-core/src/index.d.ts +160 -0
  39. package/templates/dist/mapper-core/src/index.js +637 -0
  40. package/templates/dist/mapper-core/src/index.js.map +1 -0
  41. package/templates/dist/testkit-core/src/errors/index.d.ts +49 -0
  42. package/templates/dist/testkit-core/src/errors/index.js +111 -0
  43. package/templates/dist/testkit-core/src/errors/index.js.map +1 -0
  44. package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.d.ts +5 -0
  45. package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.js +29 -0
  46. package/templates/dist/testkit-core/src/fixtures/ColumnAffinity.js.map +1 -0
  47. package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.d.ts +37 -0
  48. package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.js +182 -0
  49. package/templates/dist/testkit-core/src/fixtures/DdlFixtureLoader.js.map +1 -0
  50. package/templates/dist/testkit-core/src/fixtures/FixtureProvider.d.ts +20 -0
  51. package/templates/dist/testkit-core/src/fixtures/FixtureProvider.js +121 -0
  52. package/templates/dist/testkit-core/src/fixtures/FixtureProvider.js.map +1 -0
  53. package/templates/dist/testkit-core/src/fixtures/FixtureStore.d.ts +51 -0
  54. package/templates/dist/testkit-core/src/fixtures/FixtureStore.js +199 -0
  55. package/templates/dist/testkit-core/src/fixtures/FixtureStore.js.map +1 -0
  56. package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.d.ts +10 -0
  57. package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.js +28 -0
  58. package/templates/dist/testkit-core/src/fixtures/TableDefinitionSchemaRegistry.js.map +1 -0
  59. package/templates/dist/testkit-core/src/fixtures/TableNameResolver.d.ts +18 -0
  60. package/templates/dist/testkit-core/src/fixtures/TableNameResolver.js +80 -0
  61. package/templates/dist/testkit-core/src/fixtures/TableNameResolver.js.map +1 -0
  62. package/templates/dist/testkit-core/src/fixtures/ddlLint.d.ts +59 -0
  63. package/templates/dist/testkit-core/src/fixtures/ddlLint.js +489 -0
  64. package/templates/dist/testkit-core/src/fixtures/ddlLint.js.map +1 -0
  65. package/templates/dist/testkit-core/src/fixtures/naming.d.ts +1 -0
  66. package/templates/dist/testkit-core/src/fixtures/naming.js +6 -0
  67. package/templates/dist/testkit-core/src/fixtures/naming.js.map +1 -0
  68. package/templates/dist/testkit-core/src/index.d.ts +17 -0
  69. package/templates/dist/testkit-core/src/index.js +47 -0
  70. package/templates/dist/testkit-core/src/index.js.map +1 -0
  71. package/templates/dist/testkit-core/src/logger/NoopLogger.d.ts +8 -0
  72. package/templates/dist/testkit-core/src/logger/NoopLogger.js +16 -0
  73. package/templates/dist/testkit-core/src/logger/NoopLogger.js.map +1 -0
  74. package/templates/dist/testkit-core/src/provider/TestkitProvider.d.ts +57 -0
  75. package/templates/dist/testkit-core/src/provider/TestkitProvider.js +149 -0
  76. package/templates/dist/testkit-core/src/provider/TestkitProvider.js.map +1 -0
  77. package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.d.ts +43 -0
  78. package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.js +473 -0
  79. package/templates/dist/testkit-core/src/rewriter/ResultSelectRewriter.js.map +1 -0
  80. package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.d.ts +9 -0
  81. package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.js +38 -0
  82. package/templates/dist/testkit-core/src/rewriter/SelectAnalyzer.js.map +1 -0
  83. package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.d.ts +42 -0
  84. package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.js +298 -0
  85. package/templates/dist/testkit-core/src/rewriter/SelectFixtureRewriter.js.map +1 -0
  86. package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.d.ts +12 -0
  87. package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.js +63 -0
  88. package/templates/dist/testkit-core/src/sql/SqliteValuesBuilder.js.map +1 -0
  89. package/templates/dist/testkit-core/src/types/index.d.ts +69 -0
  90. package/templates/dist/testkit-core/src/types/index.js +3 -0
  91. package/templates/dist/testkit-core/src/types/index.js.map +1 -0
  92. package/templates/dist/testkit-core/src/utils/queryHelpers.d.ts +28 -0
  93. package/templates/dist/testkit-core/src/utils/queryHelpers.js +81 -0
  94. package/templates/dist/testkit-core/src/utils/queryHelpers.js.map +1 -0
  95. package/templates/dist/writer-core/src/index.d.ts +34 -0
  96. package/templates/dist/writer-core/src/index.js +115 -0
  97. package/templates/dist/writer-core/src/index.js.map +1 -0
  98. package/templates/dist/ztd-cli/templates/src/db/sql-client.d.ts +20 -0
  99. package/templates/dist/ztd-cli/templates/src/db/sql-client.js +3 -0
  100. package/templates/dist/ztd-cli/templates/src/db/sql-client.js.map +1 -0
  101. package/templates/dist/ztd-cli/templates/src/db/sql-client.ts +24 -0
  102. package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.d.ts +36 -0
  103. package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.js +85 -0
  104. package/templates/dist/ztd-cli/templates/src/repositories/user-accounts.js.map +1 -0
  105. package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.d.ts +20 -0
  106. package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.js +33 -0
  107. package/templates/dist/ztd-cli/templates/tests/generated/ztd-row-map.generated.js.map +1 -0
  108. package/templates/dist/ztd-cli/templates/tests/support/global-setup.d.ts +10 -0
  109. package/templates/dist/ztd-cli/templates/tests/support/global-setup.js +29 -0
  110. package/templates/dist/ztd-cli/templates/tests/support/global-setup.js.map +1 -0
  111. package/templates/dist/ztd-cli/templates/tests/support/testkit-client.d.ts +66 -0
  112. package/templates/dist/ztd-cli/templates/tests/support/testkit-client.js +552 -0
  113. package/templates/dist/ztd-cli/templates/tests/support/testkit-client.js.map +1 -0
  114. package/templates/dist/ztd-cli/templates/tests/user-profiles.test.d.ts +1 -0
  115. package/templates/dist/ztd-cli/templates/tests/user-profiles.test.js +82 -0
  116. package/templates/dist/ztd-cli/templates/tests/user-profiles.test.js.map +1 -0
  117. package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.d.ts +1 -0
  118. package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.js +29 -0
  119. package/templates/dist/ztd-cli/templates/tests/writer-constraints.test.js.map +1 -0
  120. package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.d.ts +7 -0
  121. package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.js +10 -0
  122. package/templates/dist/ztd-cli/templates/tests/ztd-layout.generated.js.map +1 -0
  123. package/templates/src/AGENTS.md +26 -0
  124. package/templates/src/catalog/AGENTS.md +37 -0
  125. package/templates/src/catalog/runtime/AGENTS.md +75 -0
  126. package/templates/src/catalog/runtime/_coercions.ts +1 -0
  127. package/templates/src/catalog/runtime/_smoke.runtime.ts +21 -0
  128. package/templates/src/catalog/specs/AGENTS.md +48 -0
  129. package/templates/src/catalog/specs/_smoke.spec.arktype.ts +21 -0
  130. package/templates/src/catalog/specs/_smoke.spec.zod.ts +20 -0
  131. package/templates/src/db/sql-client.ts +5 -5
  132. package/templates/src/jobs/AGENTS.md +26 -0
  133. package/templates/src/jobs/README.md +3 -0
  134. package/templates/src/repositories/AGENTS.md +118 -0
  135. package/templates/src/repositories/tables/AGENTS.md +94 -0
  136. package/templates/src/repositories/tables/README.md +3 -0
  137. package/templates/src/repositories/views/AGENTS.md +25 -0
  138. package/templates/src/repositories/views/README.md +3 -0
  139. package/templates/src/sql/AGENTS.md +77 -0
  140. package/templates/src/sql/README.md +6 -0
  141. package/templates/tests/AGENTS.md +43 -129
  142. package/templates/tests/generated/AGENTS.md +16 -0
  143. package/templates/tests/smoke.test.ts +5 -0
  144. package/templates/tests/smoke.validation.test.ts +34 -0
  145. package/templates/tests/support/AGENTS.md +26 -0
  146. package/templates/tests/support/global-setup.ts +8 -23
  147. package/templates/tests/support/testkit-client.ts +13 -741
  148. package/templates/tests/ztd-layout.generated.ts +0 -2
  149. package/templates/tsconfig.json +9 -3
  150. package/templates/ztd/AGENTS.md +11 -142
  151. package/templates/ztd/README.md +4 -82
  152. package/templates/ztd/ddl/AGENTS.md +34 -0
  153. package/templates/ztd/ddl/demo.sql +74 -0
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createConsolePrompter = createConsolePrompter;
7
7
  exports.runInitCommand = runInitCommand;
8
+ exports.normalizeSchemaName = normalizeSchemaName;
9
+ exports.sanitizeSchemaFileName = sanitizeSchemaFileName;
8
10
  exports.registerInitCommand = registerInitCommand;
9
11
  const node_child_process_1 = require("node:child_process");
10
12
  const node_fs_1 = require("node:fs");
@@ -15,7 +17,6 @@ const agents_1 = require("../utils/agents");
15
17
  const ztdProjectConfig_1 = require("../utils/ztdProjectConfig");
16
18
  const ztdConfig_1 = require("./ztdConfig");
17
19
  const pull_1 = require("./pull");
18
- const options_1 = require("./options");
19
20
  /**
20
21
  * Create a readline-backed prompter that reads from stdin/stdout.
21
22
  */
@@ -28,6 +29,11 @@ function createConsolePrompter() {
28
29
  async function requestLine(question) {
29
30
  return (await rl.question(question)).trim();
30
31
  }
32
+ async function requestLineWithDefault(question, defaultValue, example) {
33
+ const prompt = `${question}${example ? ` (${example})` : ''} [default: ${defaultValue}]: `;
34
+ const answer = await requestLine(prompt);
35
+ return answer.length > 0 ? answer : defaultValue;
36
+ }
31
37
  return {
32
38
  async selectChoice(question, choices) {
33
39
  while (true) {
@@ -52,6 +58,9 @@ function createConsolePrompter() {
52
58
  console.log('This value cannot be empty.');
53
59
  }
54
60
  },
61
+ async promptInputWithDefault(question, defaultValue, example) {
62
+ return requestLineWithDefault(question, defaultValue, example);
63
+ },
55
64
  async confirm(question) {
56
65
  while (true) {
57
66
  const answer = (await requestLine(`${question} (y/N): `)).toLowerCase();
@@ -72,24 +81,64 @@ function createConsolePrompter() {
72
81
  }
73
82
  };
74
83
  }
75
- const SAMPLE_SCHEMA = `CREATE TABLE public.example (
76
- id serial PRIMARY KEY,
77
- name text NOT NULL
78
- );
79
- `;
84
+ const MANDATORY_TESTKIT_DEPENDENCIES = {
85
+ '@rawsql-ts/adapter-node-pg': '^0.15.1',
86
+ '@rawsql-ts/testkit-postgres': '^0.15.1'
87
+ };
88
+ const SQL_CONTRACT_DEPENDENCY = {
89
+ '@rawsql-ts/sql-contract': '^0.1.0'
90
+ };
91
+ const ZOD_DEPENDENCY = {
92
+ zod: '^4.3.6'
93
+ };
94
+ const ARKTYPE_DEPENDENCY = {
95
+ arktype: '^2.1.29'
96
+ };
97
+ async function gatherOptionalFeatures(prompter, _dependencies) {
98
+ const validatorChoice = await prompter.selectChoice('Runtime DTO validation is required for ZTD tests. Which validator backend should we install?', ['Zod (zod, recommended)', 'ArkType (arktype)']);
99
+ const validator = validatorChoice === 0 ? 'zod' : 'arktype';
100
+ return { validator };
101
+ }
80
102
  const README_TEMPLATE = 'README.md';
81
- const TESTS_CONFIG_TEMPLATE = 'tests/ztd-layout.generated.ts';
82
103
  const TESTS_AGENTS_TEMPLATE = 'tests/AGENTS.md';
104
+ const TESTS_SUPPORT_AGENTS_TEMPLATE = 'tests/support/AGENTS.md';
105
+ const TESTS_GENERATED_AGENTS_TEMPLATE = 'tests/generated/AGENTS.md';
106
+ const SMOKE_SPEC_ZOD_TEMPLATE = 'src/catalog/specs/_smoke.spec.zod.ts';
107
+ const SMOKE_SPEC_ARKTYPE_TEMPLATE = 'src/catalog/specs/_smoke.spec.arktype.ts';
108
+ const SMOKE_COERCIONS_TEMPLATE = 'src/catalog/runtime/_coercions.ts';
109
+ const SMOKE_RUNTIME_TEMPLATE = 'src/catalog/runtime/_smoke.runtime.ts';
110
+ const SMOKE_VALIDATION_TEST_TEMPLATE = 'tests/smoke.validation.test.ts';
111
+ const TESTS_SMOKE_TEMPLATE = 'tests/smoke.test.ts';
83
112
  const TESTKIT_CLIENT_TEMPLATE = 'tests/support/testkit-client.ts';
84
113
  const GLOBAL_SETUP_TEMPLATE = 'tests/support/global-setup.ts';
85
114
  const VITEST_CONFIG_TEMPLATE = 'vitest.config.ts';
115
+ const TSCONFIG_TEMPLATE = 'tsconfig.json';
86
116
  const SQL_CLIENT_TEMPLATE = 'src/db/sql-client.ts';
87
- const NEXT_STEPS = [
88
- ' 1. Review the schema files under ztd/ddl/<schema>.sql',
89
- ' 2. Inspect tests/generated/ztd-layout.generated.ts for the SQL layout',
90
- ' 3. Run npx ztd ztd-config',
91
- ' 4. Run ZTD tests with pg-testkit'
92
- ];
117
+ const SQL_README_TEMPLATE = 'src/sql/README.md';
118
+ const VIEWS_REPO_README_TEMPLATE = 'src/repositories/views/README.md';
119
+ const TABLES_REPO_README_TEMPLATE = 'src/repositories/tables/README.md';
120
+ const JOBS_README_TEMPLATE = 'src/jobs/README.md';
121
+ const SRC_AGENTS_TEMPLATE = 'src/AGENTS.md';
122
+ const SRC_CATALOG_AGENTS_TEMPLATE = 'src/catalog/AGENTS.md';
123
+ const SRC_CATALOG_RUNTIME_AGENTS_TEMPLATE = 'src/catalog/runtime/AGENTS.md';
124
+ const SRC_CATALOG_SPECS_AGENTS_TEMPLATE = 'src/catalog/specs/AGENTS.md';
125
+ const SRC_SQL_AGENTS_TEMPLATE = 'src/sql/AGENTS.md';
126
+ const SRC_REPOS_AGENTS_TEMPLATE = 'src/repositories/AGENTS.md';
127
+ const VIEWS_REPO_AGENTS_TEMPLATE = 'src/repositories/views/AGENTS.md';
128
+ const TABLES_REPO_AGENTS_TEMPLATE = 'src/repositories/tables/AGENTS.md';
129
+ const JOBS_AGENTS_TEMPLATE = 'src/jobs/AGENTS.md';
130
+ const ZTD_AGENTS_TEMPLATE = 'ztd/AGENTS.md';
131
+ const ZTD_README_TEMPLATE = 'ztd/README.md';
132
+ const ZTD_DDL_AGENTS_TEMPLATE = 'ztd/ddl/AGENTS.md';
133
+ const ZTD_DDL_DEMO_TEMPLATE = 'ztd/ddl/demo.sql';
134
+ const EMPTY_SCHEMA_COMMENT = (schemaName) => [
135
+ `-- DDL for schema "${schemaName}".`,
136
+ '-- Add CREATE TABLE statements here.',
137
+ ''
138
+ ].join('\n');
139
+ const DEMO_SCHEMA_TEMPLATE = (_schemaName) => {
140
+ return loadTemplate(ZTD_DDL_DEMO_TEMPLATE);
141
+ };
93
142
  const AGENTS_FILE_CANDIDATES = ['AGENTS.md', 'AGENTS_ztd.md'];
94
143
  const APP_INTERFACE_SECTION_MARKER = '## Application Interface Guidance';
95
144
  const APP_INTERFACE_SECTION = `---
@@ -184,26 +233,67 @@ const DEFAULT_DEPENDENCIES = {
184
233
  * Run the interactive `ztd init` workflow and return the resulting summary.
185
234
  */
186
235
  async function runInitCommand(prompter, options) {
187
- var _a, _b;
236
+ var _a, _b, _c, _d;
188
237
  const rootDir = (_a = options === null || options === void 0 ? void 0 : options.rootDir) !== null && _a !== void 0 ? _a : process.cwd();
189
238
  const dependencies = {
190
239
  ...DEFAULT_DEPENDENCIES,
191
240
  ...((_b = options === null || options === void 0 ? void 0 : options.dependencies) !== null && _b !== void 0 ? _b : {})
192
241
  };
193
- const schemaFileName = `${ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.ddl.defaultSchema}.sql`;
242
+ const overwritePolicy = {
243
+ force: (_c = options === null || options === void 0 ? void 0 : options.forceOverwrite) !== null && _c !== void 0 ? _c : false,
244
+ nonInteractive: (_d = options === null || options === void 0 ? void 0 : options.nonInteractive) !== null && _d !== void 0 ? _d : false
245
+ };
246
+ if (options === null || options === void 0 ? void 0 : options.withAppInterface) {
247
+ // Provide the documentation-only path before triggering any scaffolding work.
248
+ const summary = await appendAppInterfaceGuidance(rootDir, dependencies);
249
+ dependencies.log(`Appended application interface guidance to ${summary.relativePath}.`);
250
+ return {
251
+ summary: `App interface guidance appended to ${summary.relativePath}.`,
252
+ files: [summary]
253
+ };
254
+ }
255
+ // Ask how the user prefers to populate the initial schema.
256
+ const workflowChoice = await prompter.selectChoice('How do you want to start your database workflow?', [
257
+ 'Pull schema from Postgres (pg_dump)',
258
+ 'Create empty scaffold (I will write DDL)',
259
+ 'Create scaffold with demo DDL (no app code)'
260
+ ]);
261
+ const workflow = workflowChoice === 0 ? 'pg_dump' : workflowChoice === 1 ? 'empty' : 'demo';
262
+ const schemaName = normalizeSchemaName(ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.ddl.defaultSchema);
263
+ const schemaFileName = `${sanitizeSchemaFileName(schemaName)}.sql`;
194
264
  const absolutePaths = {
195
265
  schema: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.ddlDir, schemaFileName),
196
266
  config: node_path_1.default.join(rootDir, 'ztd.config.json'),
197
- ztdConfig: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'generated', 'ztd-row-map.generated.ts'),
198
- testsConfig: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'generated', 'ztd-layout.generated.ts'),
267
+ smokeSpec: node_path_1.default.join(rootDir, 'src', 'catalog', 'specs', '_smoke.spec.ts'),
268
+ smokeCoercions: node_path_1.default.join(rootDir, 'src', 'catalog', 'runtime', '_coercions.ts'),
269
+ smokeRuntime: node_path_1.default.join(rootDir, 'src', 'catalog', 'runtime', '_smoke.runtime.ts'),
270
+ smokeValidationTest: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'smoke.validation.test.ts'),
199
271
  testsAgents: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'AGENTS.md'),
272
+ testsSupportAgents: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'support', 'AGENTS.md'),
273
+ testsGeneratedAgents: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'generated', 'AGENTS.md'),
274
+ testsSmoke: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'smoke.test.ts'),
200
275
  readme: node_path_1.default.join(rootDir, 'README.md'),
276
+ sqlReadme: node_path_1.default.join(rootDir, 'src', 'sql', 'README.md'),
277
+ viewsRepoReadme: node_path_1.default.join(rootDir, 'src', 'repositories', 'views', 'README.md'),
278
+ tablesRepoReadme: node_path_1.default.join(rootDir, 'src', 'repositories', 'tables', 'README.md'),
279
+ jobsReadme: node_path_1.default.join(rootDir, 'src', 'jobs', 'README.md'),
280
+ srcAgents: node_path_1.default.join(rootDir, 'src', 'AGENTS.md'),
281
+ srcCatalogAgents: node_path_1.default.join(rootDir, 'src', 'catalog', 'AGENTS.md'),
282
+ srcCatalogRuntimeAgents: node_path_1.default.join(rootDir, 'src', 'catalog', 'runtime', 'AGENTS.md'),
283
+ srcCatalogSpecsAgents: node_path_1.default.join(rootDir, 'src', 'catalog', 'specs', 'AGENTS.md'),
284
+ srcSqlAgents: node_path_1.default.join(rootDir, 'src', 'sql', 'AGENTS.md'),
285
+ srcReposAgents: node_path_1.default.join(rootDir, 'src', 'repositories', 'AGENTS.md'),
286
+ viewsRepoAgents: node_path_1.default.join(rootDir, 'src', 'repositories', 'views', 'AGENTS.md'),
287
+ tablesRepoAgents: node_path_1.default.join(rootDir, 'src', 'repositories', 'tables', 'AGENTS.md'),
288
+ jobsAgents: node_path_1.default.join(rootDir, 'src', 'jobs', 'AGENTS.md'),
201
289
  sqlClient: node_path_1.default.join(rootDir, 'src', 'db', 'sql-client.ts'),
202
290
  testkitClient: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'support', 'testkit-client.ts'),
203
291
  globalSetup: node_path_1.default.join(rootDir, ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.testsDir, 'support', 'global-setup.ts'),
204
292
  vitestConfig: node_path_1.default.join(rootDir, 'vitest.config.ts'),
293
+ tsconfig: node_path_1.default.join(rootDir, 'tsconfig.json'),
205
294
  ztdDocsAgent: node_path_1.default.join(rootDir, 'ztd', 'AGENTS.md'),
206
295
  ztdDocsReadme: node_path_1.default.join(rootDir, 'ztd', 'README.md'),
296
+ ztdDdlAgents: node_path_1.default.join(rootDir, 'ztd', 'ddl', 'AGENTS.md'),
207
297
  agents: node_path_1.default.join(rootDir, 'AGENTS.md'),
208
298
  gitignore: node_path_1.default.join(rootDir, '.gitignore'),
209
299
  editorconfig: node_path_1.default.join(rootDir, '.editorconfig'),
@@ -213,116 +303,171 @@ async function runInitCommand(prompter, options) {
213
303
  };
214
304
  const relativePath = (key) => node_path_1.default.relative(rootDir, absolutePaths[key]).replace(/\\/g, '/') || absolutePaths[key];
215
305
  const summaries = {};
216
- if (options === null || options === void 0 ? void 0 : options.withAppInterface) {
217
- // Provide the documentation-only path before triggering any scaffolding work.
218
- const summary = await appendAppInterfaceGuidance(rootDir, dependencies);
219
- dependencies.log(`Appended application interface guidance to ${summary.relativePath}.`);
220
- return {
221
- summary: `App interface guidance appended to ${summary.relativePath}.`,
222
- files: [summary]
223
- };
224
- }
225
306
  // Ask how the user prefers to populate the initial schema.
226
- const workflow = await prompter.selectChoice('How do you want to start your database workflow?', ['Pull schema from Postgres (DDL-first)', 'Write DDL manually']);
227
- if (workflow === 0) {
307
+ if (workflow === 'pg_dump') {
228
308
  // Database-first path: pull the schema before writing any DDL files.
229
309
  if (!dependencies.checkPgDump()) {
230
310
  throw new Error('Unable to find pg_dump. Install Postgres or set PG_DUMP_PATH before running ztd init.');
231
311
  }
232
312
  const connectionString = await prompter.promptInput('Enter the Postgres connection string for your database', 'postgres://user:pass@host:5432/db');
233
- const schemaSummary = await writeFileWithConsent(absolutePaths.schema, relativePath('schema'), dependencies, prompter, async () => {
313
+ const schemaSummary = await writeFileWithConsent(absolutePaths.schema, relativePath('schema'), dependencies, prompter, overwritePolicy, async () => {
234
314
  dependencies.ensureDirectory(node_path_1.default.dirname(absolutePaths.schema));
235
315
  await dependencies.runPullSchema({
236
316
  url: connectionString,
237
- out: node_path_1.default.dirname(absolutePaths.schema)
317
+ out: node_path_1.default.dirname(absolutePaths.schema),
318
+ schemas: [schemaName]
238
319
  });
239
320
  });
240
321
  summaries.schema = schemaSummary;
241
322
  }
242
- else {
323
+ else if (workflow === 'empty') {
243
324
  // Manual path: seed the DDL directory with a starter schema so ztd-config can run.
244
- const schemaSummary = await writeFileWithConsent(absolutePaths.schema, relativePath('schema'), dependencies, prompter, async () => {
325
+ const schemaSummary = await writeFileWithConsent(absolutePaths.schema, relativePath('schema'), dependencies, prompter, overwritePolicy, async () => {
245
326
  dependencies.ensureDirectory(node_path_1.default.dirname(absolutePaths.schema));
246
- dependencies.writeFile(absolutePaths.schema, SAMPLE_SCHEMA);
327
+ dependencies.writeFile(absolutePaths.schema, EMPTY_SCHEMA_COMMENT(schemaName));
328
+ });
329
+ summaries.schema = schemaSummary;
330
+ }
331
+ else {
332
+ const schemaSummary = await writeFileWithConsent(absolutePaths.schema, relativePath('schema'), dependencies, prompter, overwritePolicy, async () => {
333
+ dependencies.ensureDirectory(node_path_1.default.dirname(absolutePaths.schema));
334
+ dependencies.writeFile(absolutePaths.schema, DEMO_SCHEMA_TEMPLATE(schemaName));
247
335
  });
248
336
  summaries.schema = schemaSummary;
249
337
  }
250
338
  // Seed the ztd.config.json defaults so downstream tooling knows where ddl/tests live.
251
- const configSummary = await writeFileWithConsent(absolutePaths.config, relativePath('config'), dependencies, prompter, () => {
252
- (0, ztdProjectConfig_1.writeZtdProjectConfig)(rootDir);
339
+ const configSummary = await writeFileWithConsent(absolutePaths.config, relativePath('config'), dependencies, prompter, overwritePolicy, () => {
340
+ (0, ztdProjectConfig_1.writeZtdProjectConfig)(rootDir, {
341
+ ddl: {
342
+ defaultSchema: schemaName,
343
+ searchPath: [schemaName]
344
+ }
345
+ });
253
346
  });
254
347
  summaries.config = configSummary;
255
- const projectConfig = (0, ztdProjectConfig_1.loadZtdProjectConfig)(rootDir);
256
- const ztdConfigTarget = await confirmOverwriteIfExists(absolutePaths.ztdConfig, relativePath('ztdConfig'), dependencies, prompter);
257
- if (ztdConfigTarget.write) {
258
- // Regenerate tests/generated/ztd-row-map.generated.ts so TestRowMap reflects the DDL snapshot.
259
- dependencies.ensureDirectory(node_path_1.default.dirname(absolutePaths.ztdConfig));
260
- await dependencies.runGenerateZtdConfig({
261
- directories: [node_path_1.default.resolve(node_path_1.default.dirname(absolutePaths.schema))],
262
- extensions: options_1.DEFAULT_EXTENSIONS,
263
- out: absolutePaths.ztdConfig,
264
- defaultSchema: projectConfig.ddl.defaultSchema,
265
- searchPath: projectConfig.ddl.searchPath,
266
- ddlLint: projectConfig.ddlLint
267
- });
268
- }
269
- else {
270
- dependencies.log('Skipping ZTD config generation; existing tests/generated/ztd-row-map.generated.ts preserved.');
271
- }
272
- summaries.ztdConfig = {
273
- relativePath: relativePath('ztdConfig'),
274
- outcome: ztdConfigTarget.existed
275
- ? ztdConfigTarget.write
276
- ? 'overwritten'
277
- : 'unchanged'
278
- : 'created'
279
- };
348
+ const optionalFeatures = await gatherOptionalFeatures(prompter, dependencies);
280
349
  // Emit supporting documentation that describes the workflow for contributors.
281
- const readmeSummary = await writeTemplateFile(rootDir, absolutePaths.readme, relativePath('readme'), README_TEMPLATE, dependencies, prompter, true);
350
+ const readmeSummary = await writeTemplateFile(rootDir, absolutePaths.readme, relativePath('readme'), README_TEMPLATE, dependencies, prompter, overwritePolicy, true);
282
351
  if (readmeSummary) {
283
352
  summaries.readme = readmeSummary;
284
353
  }
285
- if (options === null || options === void 0 ? void 0 : options.withSqlClient) {
286
- const sqlClientSummary = writeOptionalTemplateFile(absolutePaths.sqlClient, relativePath('sqlClient'), SQL_CLIENT_TEMPLATE, dependencies);
287
- if (sqlClientSummary) {
288
- summaries.sqlClient = sqlClientSummary;
289
- }
354
+ const ztdDocsAgentSummary = await writeTemplateFile(rootDir, absolutePaths.ztdDocsAgent, relativePath('ztdDocsAgent'), ZTD_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
355
+ if (ztdDocsAgentSummary) {
356
+ summaries.ztdDocsAgent = ztdDocsAgentSummary;
357
+ }
358
+ const ztdDocsReadmeSummary = await writeTemplateFile(rootDir, absolutePaths.ztdDocsReadme, relativePath('ztdDocsReadme'), ZTD_README_TEMPLATE, dependencies, prompter, overwritePolicy);
359
+ if (ztdDocsReadmeSummary) {
360
+ summaries.ztdDocsReadme = ztdDocsReadmeSummary;
361
+ }
362
+ const ztdDdlAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.ztdDdlAgents, relativePath('ztdDdlAgents'), ZTD_DDL_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
363
+ if (ztdDdlAgentsSummary) {
364
+ summaries.ztdDdlAgents = ztdDdlAgentsSummary;
365
+ }
366
+ const srcAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.srcAgents, relativePath('srcAgents'), SRC_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
367
+ if (srcAgentsSummary) {
368
+ summaries.srcAgents = srcAgentsSummary;
369
+ }
370
+ const srcCatalogAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.srcCatalogAgents, relativePath('srcCatalogAgents'), SRC_CATALOG_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
371
+ if (srcCatalogAgentsSummary) {
372
+ summaries.srcCatalogAgents = srcCatalogAgentsSummary;
373
+ }
374
+ const srcCatalogRuntimeAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.srcCatalogRuntimeAgents, relativePath('srcCatalogRuntimeAgents'), SRC_CATALOG_RUNTIME_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
375
+ if (srcCatalogRuntimeAgentsSummary) {
376
+ summaries.srcCatalogRuntimeAgents = srcCatalogRuntimeAgentsSummary;
377
+ }
378
+ const srcCatalogSpecsAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.srcCatalogSpecsAgents, relativePath('srcCatalogSpecsAgents'), SRC_CATALOG_SPECS_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
379
+ if (srcCatalogSpecsAgentsSummary) {
380
+ summaries.srcCatalogSpecsAgents = srcCatalogSpecsAgentsSummary;
381
+ }
382
+ const srcSqlAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.srcSqlAgents, relativePath('srcSqlAgents'), SRC_SQL_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
383
+ if (srcSqlAgentsSummary) {
384
+ summaries.srcSqlAgents = srcSqlAgentsSummary;
385
+ }
386
+ const srcReposAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.srcReposAgents, relativePath('srcReposAgents'), SRC_REPOS_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
387
+ if (srcReposAgentsSummary) {
388
+ summaries.srcReposAgents = srcReposAgentsSummary;
389
+ }
390
+ const viewsRepoAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.viewsRepoAgents, relativePath('viewsRepoAgents'), VIEWS_REPO_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
391
+ if (viewsRepoAgentsSummary) {
392
+ summaries.viewsRepoAgents = viewsRepoAgentsSummary;
393
+ }
394
+ const tablesRepoAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.tablesRepoAgents, relativePath('tablesRepoAgents'), TABLES_REPO_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
395
+ if (tablesRepoAgentsSummary) {
396
+ summaries.tablesRepoAgents = tablesRepoAgentsSummary;
397
+ }
398
+ const jobsAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.jobsAgents, relativePath('jobsAgents'), JOBS_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
399
+ if (jobsAgentsSummary) {
400
+ summaries.jobsAgents = jobsAgentsSummary;
401
+ }
402
+ const sqlReadmeSummary = await writeTemplateFile(rootDir, absolutePaths.sqlReadme, relativePath('sqlReadme'), SQL_README_TEMPLATE, dependencies, prompter, overwritePolicy);
403
+ if (sqlReadmeSummary) {
404
+ summaries.sqlReadme = sqlReadmeSummary;
405
+ }
406
+ const viewsRepoReadmeSummary = await writeTemplateFile(rootDir, absolutePaths.viewsRepoReadme, relativePath('viewsRepoReadme'), VIEWS_REPO_README_TEMPLATE, dependencies, prompter, overwritePolicy);
407
+ if (viewsRepoReadmeSummary) {
408
+ summaries.viewsRepoReadme = viewsRepoReadmeSummary;
409
+ }
410
+ const tablesRepoReadmeSummary = await writeTemplateFile(rootDir, absolutePaths.tablesRepoReadme, relativePath('tablesRepoReadme'), TABLES_REPO_README_TEMPLATE, dependencies, prompter, overwritePolicy);
411
+ if (tablesRepoReadmeSummary) {
412
+ summaries.tablesRepoReadme = tablesRepoReadmeSummary;
413
+ }
414
+ const jobsReadmeSummary = await writeTemplateFile(rootDir, absolutePaths.jobsReadme, relativePath('jobsReadme'), JOBS_README_TEMPLATE, dependencies, prompter, overwritePolicy);
415
+ if (jobsReadmeSummary) {
416
+ summaries.jobsReadme = jobsReadmeSummary;
290
417
  }
291
- const testkitSummary = await writeTemplateFile(rootDir, absolutePaths.testkitClient, relativePath('testkitClient'), TESTKIT_CLIENT_TEMPLATE, dependencies, prompter);
418
+ const smokeSpecTemplate = optionalFeatures.validator === 'zod' ? SMOKE_SPEC_ZOD_TEMPLATE : SMOKE_SPEC_ARKTYPE_TEMPLATE;
419
+ const smokeSpecSummary = await writeTemplateFile(rootDir, absolutePaths.smokeSpec, relativePath('smokeSpec'), smokeSpecTemplate, dependencies, prompter, overwritePolicy);
420
+ if (smokeSpecSummary) {
421
+ summaries.smokeSpec = smokeSpecSummary;
422
+ }
423
+ const smokeCoercionsSummary = await writeTemplateFile(rootDir, absolutePaths.smokeCoercions, relativePath('smokeCoercions'), SMOKE_COERCIONS_TEMPLATE, dependencies, prompter, overwritePolicy);
424
+ if (smokeCoercionsSummary) {
425
+ summaries.smokeCoercions = smokeCoercionsSummary;
426
+ }
427
+ const smokeRuntimeSummary = await writeTemplateFile(rootDir, absolutePaths.smokeRuntime, relativePath('smokeRuntime'), SMOKE_RUNTIME_TEMPLATE, dependencies, prompter, overwritePolicy);
428
+ if (smokeRuntimeSummary) {
429
+ summaries.smokeRuntime = smokeRuntimeSummary;
430
+ }
431
+ const smokeValidationTestSummary = await writeTemplateFile(rootDir, absolutePaths.smokeValidationTest, relativePath('smokeValidationTest'), SMOKE_VALIDATION_TEST_TEMPLATE, dependencies, prompter, overwritePolicy);
432
+ if (smokeValidationTestSummary) {
433
+ summaries.smokeValidationTest = smokeValidationTestSummary;
434
+ }
435
+ const sqlClientSummary = writeOptionalTemplateFile(absolutePaths.sqlClient, relativePath('sqlClient'), SQL_CLIENT_TEMPLATE, dependencies);
436
+ if (sqlClientSummary) {
437
+ summaries.sqlClient = sqlClientSummary;
438
+ }
439
+ const testsAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.testsAgents, relativePath('testsAgents'), TESTS_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
440
+ if (testsAgentsSummary) {
441
+ summaries.testsAgents = testsAgentsSummary;
442
+ }
443
+ const testsSupportAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.testsSupportAgents, relativePath('testsSupportAgents'), TESTS_SUPPORT_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
444
+ if (testsSupportAgentsSummary) {
445
+ summaries.testsSupportAgents = testsSupportAgentsSummary;
446
+ }
447
+ const testsGeneratedAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.testsGeneratedAgents, relativePath('testsGeneratedAgents'), TESTS_GENERATED_AGENTS_TEMPLATE, dependencies, prompter, overwritePolicy);
448
+ if (testsGeneratedAgentsSummary) {
449
+ summaries.testsGeneratedAgents = testsGeneratedAgentsSummary;
450
+ }
451
+ const testsSmokeSummary = await writeTemplateFile(rootDir, absolutePaths.testsSmoke, relativePath('testsSmoke'), TESTS_SMOKE_TEMPLATE, dependencies, prompter, overwritePolicy);
452
+ if (testsSmokeSummary) {
453
+ summaries.testsSmoke = testsSmokeSummary;
454
+ }
455
+ const testkitSummary = await writeTemplateFile(rootDir, absolutePaths.testkitClient, relativePath('testkitClient'), TESTKIT_CLIENT_TEMPLATE, dependencies, prompter, overwritePolicy);
292
456
  if (testkitSummary) {
293
457
  summaries.testkitClient = testkitSummary;
294
458
  }
295
- const globalSetupSummary = await writeTemplateFile(rootDir, absolutePaths.globalSetup, relativePath('globalSetup'), GLOBAL_SETUP_TEMPLATE, dependencies, prompter);
459
+ const globalSetupSummary = await writeTemplateFile(rootDir, absolutePaths.globalSetup, relativePath('globalSetup'), GLOBAL_SETUP_TEMPLATE, dependencies, prompter, overwritePolicy);
296
460
  if (globalSetupSummary) {
297
461
  summaries.globalSetup = globalSetupSummary;
298
462
  }
299
- const vitestConfigSummary = await writeTemplateFile(rootDir, absolutePaths.vitestConfig, relativePath('vitestConfig'), VITEST_CONFIG_TEMPLATE, dependencies, prompter);
463
+ const vitestConfigSummary = await writeTemplateFile(rootDir, absolutePaths.vitestConfig, relativePath('vitestConfig'), VITEST_CONFIG_TEMPLATE, dependencies, prompter, overwritePolicy);
300
464
  if (vitestConfigSummary) {
301
465
  summaries.vitestConfig = vitestConfigSummary;
302
466
  }
303
- const testsConfigSummary = await writeTemplateFile(rootDir, absolutePaths.testsConfig, relativePath('testsConfig'), TESTS_CONFIG_TEMPLATE, dependencies, prompter);
304
- if (testsConfigSummary) {
305
- summaries.testsConfig = testsConfigSummary;
306
- }
307
- // Ensure the generated tests guidance lands beside the generated layout config.
308
- const testsAgentsSummary = await writeTemplateFile(rootDir, absolutePaths.testsAgents, relativePath('testsAgents'), TESTS_AGENTS_TEMPLATE, dependencies, prompter);
309
- if (testsAgentsSummary) {
310
- summaries.testsAgents = testsAgentsSummary;
467
+ const tsconfigSummary = await writeTemplateFile(rootDir, absolutePaths.tsconfig, relativePath('tsconfig'), TSCONFIG_TEMPLATE, dependencies, prompter, overwritePolicy);
468
+ if (tsconfigSummary) {
469
+ summaries.tsconfig = tsconfigSummary;
311
470
  }
312
- // Seed the shared guidance that lives inside the ztd/ directory so contributors see the new instructions.
313
- const ztdDocsAgentSummary = await writeTemplateFile(rootDir, absolutePaths.ztdDocsAgent, relativePath('ztdDocsAgent'), 'ztd/AGENTS.md', dependencies, prompter);
314
- if (ztdDocsAgentSummary) {
315
- summaries.ztdDocsAgent = ztdDocsAgentSummary;
316
- }
317
- // Provide the companion README inside ztd/ so maintainers understand the schema, spec, and enum intentions.
318
- const ztdDocsReadmeSummary = await writeTemplateFile(rootDir, absolutePaths.ztdDocsReadme, relativePath('ztdDocsReadme'), 'ztd/README.md', dependencies, prompter);
319
- if (ztdDocsReadmeSummary) {
320
- summaries.ztdDocsReadme = ztdDocsReadmeSummary;
321
- }
322
- const ztdRootDir = node_path_1.default.join(rootDir, 'ztd');
323
- // Ensure the domain-specs and enums anchors exist so contributors immediately see where those artifacts belong.
324
- dependencies.ensureDirectory(node_path_1.default.join(ztdRootDir, 'domain-specs'));
325
- dependencies.ensureDirectory(node_path_1.default.join(ztdRootDir, 'enums'));
326
471
  const editorconfigSummary = copyTemplateFileIfMissing(rootDir, relativePath('editorconfig'), '.editorconfig', dependencies);
327
472
  if (editorconfigSummary) {
328
473
  summaries.editorconfig = editorconfigSummary;
@@ -339,7 +484,7 @@ async function runInitCommand(prompter, options) {
339
484
  if (prettierignoreSummary) {
340
485
  summaries.prettierignore = prettierignoreSummary;
341
486
  }
342
- const packageSummary = ensurePackageJsonFormatting(rootDir, relativePath('package'), dependencies);
487
+ const packageSummary = ensurePackageJsonFormatting(rootDir, relativePath('package'), dependencies, optionalFeatures);
343
488
  if (packageSummary) {
344
489
  summaries.package = packageSummary;
345
490
  }
@@ -349,7 +494,8 @@ async function runInitCommand(prompter, options) {
349
494
  summaries.agents = agentsRelative;
350
495
  }
351
496
  await ensureTemplateDependenciesInstalled(rootDir, absolutePaths, summaries, dependencies);
352
- const summaryLines = buildSummaryLines(summaries);
497
+ const nextSteps = buildNextSteps(normalizeRelative(rootDir, absolutePaths.schema), workflow);
498
+ const summaryLines = buildSummaryLines(summaries, optionalFeatures, nextSteps);
353
499
  summaryLines.forEach(dependencies.log);
354
500
  return {
355
501
  summary: summaryLines.join('\n'),
@@ -525,7 +671,7 @@ function listDeclaredPackages(rootDir) {
525
671
  return declared;
526
672
  }
527
673
  function listTemplateReferencedPackages(absolutePaths, summaries) {
528
- const packages = new Set(['@rawsql-ts/pg-testkit']);
674
+ const packages = new Set();
529
675
  const touchedKeys = Object.entries(summaries)
530
676
  .filter((entry) => Boolean(entry[1]))
531
677
  .filter(([, summary]) => summary.outcome === 'created' || summary.outcome === 'overwritten')
@@ -548,7 +694,7 @@ async function ensureTemplateDependenciesInstalled(rootDir, absolutePaths, summa
548
694
  var _a;
549
695
  const packageJsonPath = node_path_1.default.join(rootDir, 'package.json');
550
696
  if (!dependencies.fileExists(packageJsonPath)) {
551
- dependencies.log('Skipping dependency installation because package.json is missing.');
697
+ dependencies.log('Skipping dependency installation because package.json is missing. Next: run pnpm init (or npm init), install dependencies, then run npx ztd ztd-config.');
552
698
  return;
553
699
  }
554
700
  const packageManager = detectPackageManager(rootDir);
@@ -603,18 +749,22 @@ function writeOptionalTemplateFile(absolutePath, relative, templateName, depende
603
749
  dependencies.writeFile(absolutePath, (0, node_fs_1.readFileSync)(templatePath, 'utf8'));
604
750
  return { relativePath: relative, outcome: 'created' };
605
751
  }
606
- function ensurePackageJsonFormatting(rootDir, relative, dependencies) {
752
+ function ensurePackageJsonFormatting(rootDir, relative, dependencies, optionalFeatures) {
607
753
  var _a, _b;
608
754
  const packagePath = node_path_1.default.join(rootDir, 'package.json');
609
- // Skip wiring defaults when the project does not yet have a package manifest.
610
- if (!dependencies.fileExists(packagePath)) {
611
- return null;
612
- }
613
- const document = (0, node_fs_1.readFileSync)(packagePath, 'utf8');
614
- const parsed = JSON.parse(document);
755
+ const packageExists = dependencies.fileExists(packagePath);
756
+ const parsed = packageExists
757
+ ? JSON.parse((0, node_fs_1.readFileSync)(packagePath, 'utf8'))
758
+ : {
759
+ name: inferPackageName(rootDir),
760
+ version: '0.0.0',
761
+ private: true
762
+ };
615
763
  let changed = false;
616
764
  const scripts = (_a = parsed.scripts) !== null && _a !== void 0 ? _a : {};
617
765
  const requiredScripts = {
766
+ test: 'vitest run',
767
+ typecheck: 'tsc --noEmit',
618
768
  format: 'prettier . --write',
619
769
  lint: 'eslint .',
620
770
  'lint:fix': 'eslint . --fix'
@@ -652,6 +802,11 @@ function ensurePackageJsonFormatting(rootDir, relative, dependencies) {
652
802
  'prettier-plugin-sql': '^0.19.2',
653
803
  'simple-git-hooks': '^2.13.1'
654
804
  };
805
+ const testingDeps = {
806
+ vitest: '^4.0.7',
807
+ typescript: '^5.8.2',
808
+ '@types/node': '^22.13.10'
809
+ };
655
810
  // Add the formatting toolchain dependencies that back the scripts and hooks.
656
811
  for (const [dep, version] of Object.entries(formattingDeps)) {
657
812
  if (dep in devDependencies) {
@@ -660,6 +815,31 @@ function ensurePackageJsonFormatting(rootDir, relative, dependencies) {
660
815
  devDependencies[dep] = version;
661
816
  changed = true;
662
817
  }
818
+ const stackDependencies = {
819
+ ...MANDATORY_TESTKIT_DEPENDENCIES,
820
+ ...SQL_CONTRACT_DEPENDENCY
821
+ };
822
+ if (optionalFeatures.validator === 'zod') {
823
+ Object.assign(stackDependencies, ZOD_DEPENDENCY);
824
+ }
825
+ else {
826
+ Object.assign(stackDependencies, ARKTYPE_DEPENDENCY);
827
+ }
828
+ // Ensure test and typecheck toolchain dependencies are present for a runnable scaffold.
829
+ for (const [dep, version] of Object.entries(testingDeps)) {
830
+ if (dep in devDependencies) {
831
+ continue;
832
+ }
833
+ devDependencies[dep] = version;
834
+ changed = true;
835
+ }
836
+ for (const [dep, version] of Object.entries(stackDependencies)) {
837
+ if (dep in devDependencies) {
838
+ continue;
839
+ }
840
+ devDependencies[dep] = version;
841
+ changed = true;
842
+ }
663
843
  if (!changed) {
664
844
  return null;
665
845
  }
@@ -667,42 +847,56 @@ function ensurePackageJsonFormatting(rootDir, relative, dependencies) {
667
847
  dependencies.ensureDirectory(node_path_1.default.dirname(packagePath));
668
848
  // Persist the updated manifest so the new scripts and tools are available immediately.
669
849
  dependencies.writeFile(packagePath, `${JSON.stringify(parsed, null, 2)}\n`);
670
- return { relativePath: relative, outcome: 'overwritten' };
850
+ return { relativePath: relative, outcome: packageExists ? 'overwritten' : 'created' };
851
+ }
852
+ function inferPackageName(rootDir) {
853
+ const baseName = node_path_1.default.basename(rootDir).toLowerCase();
854
+ const normalized = baseName.replace(/[^a-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
855
+ if (normalized.length > 0) {
856
+ return normalized;
857
+ }
858
+ return 'ztd-project';
671
859
  }
672
- async function writeFileWithConsent(absolutePath, relative, dependencies, prompter, writer) {
673
- const { existed, write } = await confirmOverwriteIfExists(absolutePath, relative, dependencies, prompter);
860
+ async function writeFileWithConsent(absolutePath, relative, dependencies, prompter, overwritePolicy, writer) {
861
+ const { existed, write } = await confirmOverwriteIfExists(absolutePath, relative, dependencies, prompter, overwritePolicy);
674
862
  if (!write) {
675
863
  return { relativePath: relative, outcome: 'unchanged' };
676
864
  }
677
865
  await writer();
678
866
  return { relativePath: relative, outcome: existed ? 'overwritten' : 'created' };
679
867
  }
680
- async function confirmOverwriteIfExists(absolutePath, relative, dependencies, prompter) {
868
+ async function confirmOverwriteIfExists(absolutePath, relative, dependencies, prompter, overwritePolicy) {
681
869
  const existed = dependencies.fileExists(absolutePath);
682
870
  if (!existed) {
683
871
  return { existed: false, write: true };
684
872
  }
873
+ if (overwritePolicy.force) {
874
+ return { existed: true, write: true };
875
+ }
876
+ if (overwritePolicy.nonInteractive) {
877
+ throw new Error(`File ${relative} already exists. Re-run with --yes to overwrite or remove the file before running ztd init.`);
878
+ }
685
879
  const overwrite = await prompter.confirm(`File ${relative} already exists. Overwrite?`);
686
880
  if (!overwrite) {
687
881
  return { existed: true, write: false };
688
882
  }
689
883
  return { existed: true, write: true };
690
884
  }
691
- async function writeDocFile(absolutePath, relative, contents, dependencies, prompter) {
692
- const summary = await writeFileWithConsent(absolutePath, relative, dependencies, prompter, () => {
885
+ async function writeDocFile(absolutePath, relative, contents, dependencies, prompter, overwritePolicy) {
886
+ const summary = await writeFileWithConsent(absolutePath, relative, dependencies, prompter, overwritePolicy, () => {
693
887
  dependencies.ensureDirectory(node_path_1.default.dirname(absolutePath));
694
888
  dependencies.writeFile(absolutePath, contents);
695
889
  });
696
890
  return summary;
697
891
  }
698
- async function writeTemplateFile(rootDir, absolutePath, relative, templateName, dependencies, prompter, allowFallback) {
892
+ async function writeTemplateFile(rootDir, absolutePath, relative, templateName, dependencies, prompter, overwritePolicy, allowFallback) {
699
893
  const templateTarget = resolveTemplateTarget(rootDir, absolutePath, relative, dependencies, allowFallback);
700
894
  if (!templateTarget) {
701
895
  return null;
702
896
  }
703
897
  // Load shared documentation templates so every new project gets the same guidance.
704
898
  const contents = loadTemplate(templateName);
705
- return writeDocFile(templateTarget.absolutePath, templateTarget.relativePath, contents, dependencies, prompter);
899
+ return writeDocFile(templateTarget.absolutePath, templateTarget.relativePath, contents, dependencies, prompter, overwritePolicy);
706
900
  }
707
901
  function resolveTemplateTarget(rootDir, absolutePath, relative, dependencies, allowFallback) {
708
902
  if (!dependencies.fileExists(absolutePath)) {
@@ -729,6 +923,25 @@ function normalizeRelative(rootDir, absolutePath) {
729
923
  const relative = node_path_1.default.relative(rootDir, absolutePath).replace(/\\/g, '/');
730
924
  return relative || absolutePath;
731
925
  }
926
+ /**
927
+ * Normalizes a schema identifier into the canonical lowercase form used by ztd-cli file naming.
928
+ * Empty input falls back to the configured default schema.
929
+ */
930
+ function normalizeSchemaName(value) {
931
+ const trimmed = value.trim();
932
+ if (!trimmed) {
933
+ return ztdProjectConfig_1.DEFAULT_ZTD_CONFIG.ddl.defaultSchema;
934
+ }
935
+ return trimmed.replace(/^"|"$/g, '').toLowerCase();
936
+ }
937
+ /**
938
+ * Sanitizes a normalized schema identifier so it can be used as a filesystem-safe file stem.
939
+ * Returns `schema` when all characters are stripped by sanitization.
940
+ */
941
+ function sanitizeSchemaFileName(schemaName) {
942
+ const sanitized = schemaName.replace(/[^a-z0-9_-]/g, '_').replace(/^_+|_+$/g, '');
943
+ return sanitized || 'schema';
944
+ }
732
945
  function resolveOrCreateAgentsFile(rootDir, dependencies) {
733
946
  // Prefer materializing the bundled template before looking for existing attention files.
734
947
  const templateTarget = dependencies.copyAgentsTemplate(rootDir);
@@ -771,20 +984,51 @@ function loadTemplate(templateName) {
771
984
  }
772
985
  return (0, node_fs_1.readFileSync)(templatePath, 'utf8');
773
986
  }
774
- function buildSummaryLines(summaries) {
987
+ function buildNextSteps(schemaRelativePath, workflow) {
988
+ const stepOne = workflow === 'pg_dump'
989
+ ? ` 1. Review the dumped DDL in ${schemaRelativePath}`
990
+ : ` 1. If the schema file is empty, edit ${schemaRelativePath}`;
991
+ return [
992
+ stepOne,
993
+ ' 2. Run npx ztd ztd-config',
994
+ ' 3. Provide a SqlClient implementation (adapter or mock)',
995
+ ' 4. Run tests (pnpm test or npx vitest run)'
996
+ ];
997
+ }
998
+ function buildSummaryLines(summaries, optionalFeatures, nextSteps) {
775
999
  const orderedKeys = [
776
1000
  'schema',
777
1001
  'config',
778
- 'testsConfig',
779
- 'testsAgents',
780
- 'ztdConfig',
781
1002
  'readme',
1003
+ 'ztdDocsAgent',
1004
+ 'ztdDocsReadme',
1005
+ 'ztdDdlAgents',
1006
+ 'srcAgents',
1007
+ 'srcCatalogAgents',
1008
+ 'srcCatalogRuntimeAgents',
1009
+ 'srcCatalogSpecsAgents',
1010
+ 'srcSqlAgents',
1011
+ 'srcReposAgents',
1012
+ 'viewsRepoAgents',
1013
+ 'tablesRepoAgents',
1014
+ 'jobsAgents',
1015
+ 'sqlReadme',
1016
+ 'viewsRepoReadme',
1017
+ 'tablesRepoReadme',
1018
+ 'jobsReadme',
1019
+ 'smokeSpec',
1020
+ 'smokeCoercions',
1021
+ 'smokeRuntime',
1022
+ 'smokeValidationTest',
1023
+ 'testsAgents',
1024
+ 'testsSupportAgents',
1025
+ 'testsGeneratedAgents',
1026
+ 'testsSmoke',
782
1027
  'sqlClient',
783
1028
  'testkitClient',
784
1029
  'globalSetup',
785
1030
  'vitestConfig',
786
- 'ztdDocsAgent',
787
- 'ztdDocsReadme',
1031
+ 'tsconfig',
788
1032
  'agents',
789
1033
  'gitignore',
790
1034
  'editorconfig',
@@ -804,7 +1048,13 @@ function buildSummaryLines(summaries) {
804
1048
  lines.push(` - ${summary.relativePath}${note}`);
805
1049
  }
806
1050
  }
807
- lines.push('', 'Next steps:', ...NEXT_STEPS);
1051
+ lines.push('', 'Validation configuration:');
1052
+ lines.push(' - SQL catalog/mapping support via @rawsql-ts/sql-contract (see docs/recipes/sql-contract.md)');
1053
+ const validatorLabel = optionalFeatures.validator === 'zod'
1054
+ ? 'Zod (zod, docs/recipes/validation-zod.md)'
1055
+ : 'ArkType (arktype, docs/recipes/validation-arktype.md)';
1056
+ lines.push(` - Validator backend: ${validatorLabel}`);
1057
+ lines.push('', 'Next steps:', ...nextSteps);
808
1058
  return lines;
809
1059
  }
810
1060
  function registerInitCommand(program) {
@@ -813,12 +1063,16 @@ function registerInitCommand(program) {
813
1063
  .description('Automate project setup for Zero Table Dependency workflows')
814
1064
  .option('--with-sqlclient', 'Generate a minimal SqlClient interface for repositories')
815
1065
  .option('--with-app-interface', 'Append application interface guidance to AGENTS.md only')
1066
+ .option('--yes', 'Overwrite existing scaffold files without prompting')
816
1067
  .action(async (options) => {
1068
+ var _a;
817
1069
  const prompter = createConsolePrompter();
818
1070
  try {
819
1071
  await runInitCommand(prompter, {
820
1072
  withSqlClient: options.withSqlclient,
821
- withAppInterface: options.withAppInterface
1073
+ withAppInterface: options.withAppInterface,
1074
+ forceOverwrite: (_a = options.yes) !== null && _a !== void 0 ? _a : false,
1075
+ nonInteractive: !process.stdin.isTTY
822
1076
  });
823
1077
  }
824
1078
  finally {