@solid-stack/mason 1.0.13 → 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { cac } from 'cac';
3
- import * as p15 from '@clack/prompts';
4
- import pc15 from 'picocolors';
5
- import fs12 from 'fs';
3
+ import * as p3 from '@clack/prompts';
4
+ import pc14 from 'picocolors';
5
+ import fs9 from 'fs';
6
6
  import path2 from 'path';
7
7
  import { fileURLToPath } from 'url';
8
8
  import Handlebars from 'handlebars';
@@ -12,7 +12,7 @@ import { createHash } from 'crypto';
12
12
  function writeFileSafely(absolutePath, content, options = {}) {
13
13
  const projectRoot = options.projectRoot || process.cwd();
14
14
  const relPath = path2.relative(projectRoot, absolutePath).replace(/\\/g, "/");
15
- const existedBefore = fs12.existsSync(absolutePath);
15
+ const existedBefore = fs9.existsSync(absolutePath);
16
16
  if (options.dryRun) {
17
17
  return {
18
18
  relativePath: relPath,
@@ -32,10 +32,10 @@ function writeFileSafely(absolutePath, content, options = {}) {
32
32
  };
33
33
  }
34
34
  const dir = path2.dirname(absolutePath);
35
- if (!fs12.existsSync(dir)) {
36
- fs12.mkdirSync(dir, { recursive: true });
35
+ if (!fs9.existsSync(dir)) {
36
+ fs9.mkdirSync(dir, { recursive: true });
37
37
  }
38
- fs12.writeFileSync(absolutePath, content, "utf-8");
38
+ fs9.writeFileSync(absolutePath, content, "utf-8");
39
39
  return {
40
40
  relativePath: relPath,
41
41
  absolutePath,
@@ -47,17 +47,17 @@ function writeFileSafely(absolutePath, content, options = {}) {
47
47
  function printGeneratedFiles(files, isDryRun = false) {
48
48
  console.log("");
49
49
  if (isDryRun) {
50
- p15.log.warn(pc15.yellow(pc15.bold("[DRY RUN PREVIEW] No files were written to disk.")));
50
+ p3.log.warn(pc14.yellow(pc14.bold("[DRY RUN PREVIEW] No files were written to disk.")));
51
51
  }
52
52
  for (const f of files) {
53
53
  if (f.action === "created") {
54
- p15.log.success(`${pc15.bold(f.relativePath)} ${pc15.dim("(created)")}`);
54
+ p3.log.success(`${pc14.bold(f.relativePath)} ${pc14.dim("(created)")}`);
55
55
  } else if (f.action === "overwritten") {
56
- p15.log.warn(`${pc15.bold(f.relativePath)} ${pc15.dim("(overwritten)")}`);
56
+ p3.log.warn(`${pc14.bold(f.relativePath)} ${pc14.dim("(overwritten)")}`);
57
57
  } else if (f.action === "skipped") {
58
- p15.log.info(`${pc15.dim(f.relativePath)} ${pc15.dim("(skipped - already exists, pass -o to overwrite)")}`);
58
+ p3.log.info(`${pc14.dim(f.relativePath)} ${pc14.dim("(skipped - already exists, pass -o to overwrite)")}`);
59
59
  } else {
60
- p15.log.info(`${pc15.bold(f.relativePath)} ${pc15.dim("(preview)")}`);
60
+ p3.log.info(`${pc14.bold(f.relativePath)} ${pc14.dim("(preview)")}`);
61
61
  }
62
62
  }
63
63
  }
@@ -129,9 +129,9 @@ function loadMasonConfig(startDir = process.cwd()) {
129
129
  let current = path2.resolve(startDir);
130
130
  while (true) {
131
131
  const configPath = path2.join(current, "mason.config.json");
132
- if (fs12.existsSync(configPath)) {
132
+ if (fs9.existsSync(configPath)) {
133
133
  try {
134
- return JSON.parse(fs12.readFileSync(configPath, "utf-8"));
134
+ return JSON.parse(fs9.readFileSync(configPath, "utf-8"));
135
135
  } catch {
136
136
  return null;
137
137
  }
@@ -146,7 +146,7 @@ function getEffectiveMode(projectRoot, flags) {
146
146
  if (flags?.registry) return "registry";
147
147
  const config = loadMasonConfig(projectRoot);
148
148
  if (config?.mode) return config.mode;
149
- if (fs12.existsSync(path2.join(projectRoot, "index.json")) && (fs12.existsSync(path2.join(projectRoot, "features")) || fs12.existsSync(path2.join(projectRoot, "shared"))) && !fs12.existsSync(path2.join(projectRoot, "src"))) {
149
+ if (fs9.existsSync(path2.join(projectRoot, "index.json")) && (fs9.existsSync(path2.join(projectRoot, "features")) || fs9.existsSync(path2.join(projectRoot, "shared"))) && !fs9.existsSync(path2.join(projectRoot, "src"))) {
150
150
  return "registry";
151
151
  }
152
152
  return "app";
@@ -162,7 +162,7 @@ function getConfiguredFeaturesDir(projectRoot, flags) {
162
162
  if (mode === "registry") {
163
163
  return path2.join(projectRoot, "features");
164
164
  }
165
- if (fs12.existsSync(path2.join(projectRoot, "src/features"))) {
165
+ if (fs9.existsSync(path2.join(projectRoot, "src/features"))) {
166
166
  return path2.join(projectRoot, "src/features");
167
167
  }
168
168
  return path2.join(projectRoot, "features");
@@ -178,7 +178,7 @@ function getConfiguredSharedDir(projectRoot, flags) {
178
178
  if (mode === "registry") {
179
179
  return path2.join(projectRoot, "shared");
180
180
  }
181
- if (fs12.existsSync(path2.join(projectRoot, "src/shared"))) {
181
+ if (fs9.existsSync(path2.join(projectRoot, "src/shared"))) {
182
182
  return path2.join(projectRoot, "src/shared");
183
183
  }
184
184
  return path2.join(projectRoot, "shared");
@@ -188,7 +188,7 @@ function getConfiguredSharedDir(projectRoot, flags) {
188
188
  function findProjectRoot(startDir = process.cwd()) {
189
189
  let current = path2.resolve(startDir);
190
190
  while (true) {
191
- if (fs12.existsSync(path2.join(current, "package.json"))) {
191
+ if (fs9.existsSync(path2.join(current, "package.json"))) {
192
192
  return current;
193
193
  }
194
194
  const parent = path2.dirname(current);
@@ -206,9 +206,9 @@ function resolveSharedDir(projectRoot, flags) {
206
206
  }
207
207
  function listExistingFeatures(projectRoot) {
208
208
  const featuresDir = resolveFeaturesDir(projectRoot);
209
- if (!fs12.existsSync(featuresDir)) return [];
209
+ if (!fs9.existsSync(featuresDir)) return [];
210
210
  try {
211
- const entries = fs12.readdirSync(featuresDir, { withFileTypes: true });
211
+ const entries = fs9.readdirSync(featuresDir, { withFileTypes: true });
212
212
  return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
213
213
  } catch {
214
214
  return [];
@@ -219,9 +219,9 @@ function listDomainInterfaces(projectRoot, featureName) {
219
219
  const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
220
220
  for (const feat of features) {
221
221
  const domainDir = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
222
- if (!fs12.existsSync(domainDir)) continue;
222
+ if (!fs9.existsSync(domainDir)) continue;
223
223
  try {
224
- const files = fs12.readdirSync(domainDir);
224
+ const files = fs9.readdirSync(domainDir);
225
225
  for (const file of files) {
226
226
  if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
227
227
  const name = file.replace(/\.ts$/, "");
@@ -234,7 +234,7 @@ function listDomainInterfaces(projectRoot, featureName) {
234
234
  });
235
235
  } else {
236
236
  try {
237
- const content = fs12.readFileSync(fullPath, "utf-8");
237
+ const content = fs9.readFileSync(fullPath, "utf-8");
238
238
  if (/export\s+(?:abstract\s+class|interface)\s+(\w+)/.test(content)) {
239
239
  results.push({
240
240
  name,
@@ -257,9 +257,9 @@ function listDomainEntities(projectRoot, featureName) {
257
257
  const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
258
258
  for (const feat of features) {
259
259
  const domainDir = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
260
- if (!fs12.existsSync(domainDir)) continue;
260
+ if (!fs9.existsSync(domainDir)) continue;
261
261
  try {
262
- const files = fs12.readdirSync(domainDir);
262
+ const files = fs9.readdirSync(domainDir);
263
263
  for (const file of files) {
264
264
  if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
265
265
  const name = file.replace(/\.ts$/, "");
@@ -282,9 +282,9 @@ function listUseCases(projectRoot, featureName) {
282
282
  const features = featureName ? [featureName] : listExistingFeatures(projectRoot);
283
283
  for (const feat of features) {
284
284
  const useCasesDir = path2.join(resolveFeaturesDir(projectRoot), feat, "useCases");
285
- if (!fs12.existsSync(useCasesDir)) continue;
285
+ if (!fs9.existsSync(useCasesDir)) continue;
286
286
  try {
287
- const files = fs12.readdirSync(useCasesDir);
287
+ const files = fs9.readdirSync(useCasesDir);
288
288
  for (const file of files) {
289
289
  if (file.endsWith(".ts") && !file.endsWith(".test.ts") && !file.endsWith(".d.ts")) {
290
290
  const name = file.replace(/\.ts$/, "");
@@ -316,29 +316,29 @@ hbs.registerHelper("join", (arr, sep) => {
316
316
  });
317
317
  var cachedTemplatesDir = null;
318
318
  function getTemplatesDir() {
319
- if (cachedTemplatesDir && fs12.existsSync(cachedTemplatesDir)) {
319
+ if (cachedTemplatesDir && fs9.existsSync(cachedTemplatesDir)) {
320
320
  return cachedTemplatesDir;
321
321
  }
322
322
  const currentDir = typeof __dirname !== "undefined" ? __dirname : path2.dirname(fileURLToPath(import.meta.url));
323
323
  const cand1 = path2.resolve(currentDir, "../../templates");
324
- if (fs12.existsSync(cand1)) {
324
+ if (fs9.existsSync(cand1)) {
325
325
  cachedTemplatesDir = cand1;
326
326
  return cand1;
327
327
  }
328
328
  const cand2 = path2.resolve(currentDir, "../templates");
329
- if (fs12.existsSync(cand2)) {
329
+ if (fs9.existsSync(cand2)) {
330
330
  cachedTemplatesDir = cand2;
331
331
  return cand2;
332
332
  }
333
333
  const cand3 = path2.resolve(currentDir, "templates");
334
- if (fs12.existsSync(cand3)) {
334
+ if (fs9.existsSync(cand3)) {
335
335
  cachedTemplatesDir = cand3;
336
336
  return cand3;
337
337
  }
338
338
  let curr = currentDir;
339
339
  while (true) {
340
340
  const candTemplates = path2.join(curr, "templates");
341
- if (fs12.existsSync(candTemplates)) {
341
+ if (fs9.existsSync(candTemplates)) {
342
342
  cachedTemplatesDir = candTemplates;
343
343
  return candTemplates;
344
344
  }
@@ -351,7 +351,7 @@ function getTemplatesDir() {
351
351
  var templateCache = /* @__PURE__ */ new Map();
352
352
  function loadTemplate(relativePath) {
353
353
  const fullPath = path2.isAbsolute(relativePath) ? relativePath : path2.join(getTemplatesDir(), relativePath);
354
- return fs12.readFileSync(fullPath, "utf-8");
354
+ return fs9.readFileSync(fullPath, "utf-8");
355
355
  }
356
356
  function renderTemplateFile(relativePath, context) {
357
357
  let compiled = templateCache.get(relativePath);
@@ -463,7 +463,7 @@ function generateInterfaceCode(ifaceName, kind = "abstractClass", entityName, me
463
463
  const idKey = `${entityKey}Id`;
464
464
  const listKey = `${entityKey}s`;
465
465
  const formattedCustomMethods = customMethods.map((m) => {
466
- const params = m.params && m.params.length > 0 ? m.params.map((p17) => `${p17.name}: ${p17.type}`).join("; ") : "";
466
+ const params = m.params && m.params.length > 0 ? m.params.map((p16) => `${p16.name}: ${p16.type}`).join("; ") : "";
467
467
  const returnType = m.returnType ? `Promise<${m.returnType}>` : "Promise<void>";
468
468
  return {
469
469
  name: m.name,
@@ -724,7 +724,7 @@ function parseInterfaceMethodsAndImports(content, targetIfaceName) {
724
724
  };
725
725
  }
726
726
  function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
727
- if (customPath && fs12.existsSync(customPath)) {
727
+ if (customPath && fs9.existsSync(customPath)) {
728
728
  return { filePath: customPath, ifaceName };
729
729
  }
730
730
  const candidateNames = [
@@ -735,21 +735,21 @@ function findInterfaceFile(projectRoot, ifaceName, featureName, customPath) {
735
735
  const features = featureName ? [featureName, ...listExistingFeatures(projectRoot).filter((f) => f !== featureName)] : listExistingFeatures(projectRoot);
736
736
  for (const feat of features) {
737
737
  const domainDir = path2.join(resolveFeaturesDir(projectRoot), feat, "domain");
738
- if (!fs12.existsSync(domainDir)) continue;
738
+ if (!fs9.existsSync(domainDir)) continue;
739
739
  for (const cand of candidateNames) {
740
740
  const p1 = path2.join(domainDir, `${cand}.ts`);
741
- if (fs12.existsSync(p1)) {
741
+ if (fs9.existsSync(p1)) {
742
742
  return { filePath: p1, ifaceName: cand, feature: feat };
743
743
  }
744
744
  }
745
745
  }
746
746
  for (const cand of candidateNames) {
747
747
  const p1 = path2.join(projectRoot, "domain", `${cand}.ts`);
748
- if (fs12.existsSync(p1)) return { filePath: p1, ifaceName: cand };
748
+ if (fs9.existsSync(p1)) return { filePath: p1, ifaceName: cand };
749
749
  const p22 = path2.join(projectRoot, "src", "domain", `${cand}.ts`);
750
- if (fs12.existsSync(p22)) return { filePath: p22, ifaceName: cand };
750
+ if (fs9.existsSync(p22)) return { filePath: p22, ifaceName: cand };
751
751
  const p32 = path2.join(projectRoot, "interfaces", `${cand}.ts`);
752
- if (fs12.existsSync(p32)) return { filePath: p32, ifaceName: cand };
752
+ if (fs9.existsSync(p32)) return { filePath: p32, ifaceName: cand };
753
753
  }
754
754
  return null;
755
755
  }
@@ -772,7 +772,7 @@ function loadInterfaceHierarchy(projectRoot, initialIfaceName, featureName, cust
772
772
  while (currentFile && !visited.has(currentFile)) {
773
773
  visited.add(currentFile);
774
774
  try {
775
- const content = fs12.readFileSync(currentFile, "utf-8");
775
+ const content = fs9.readFileSync(currentFile, "utf-8");
776
776
  const parsed = parseInterfaceMethodsAndImports(content, currentName);
777
777
  for (const m of parsed.methods) {
778
778
  if (!allMethods.some((existing) => existing.name === m.name)) {
@@ -1044,22 +1044,22 @@ function generateUseCaseCode(useCaseName, dependencies = [], inputProps = [], ou
1044
1044
  from: /^I[A-Z]/.test(dep) ? `../domain/${dep}.js` : `./${dep}.js`
1045
1045
  }));
1046
1046
  const domainTypesToImport = new Set(domainImports);
1047
- for (const p17 of [...inputProps, ...outputProps]) {
1048
- const rawType = p17.type.trim();
1047
+ for (const p16 of [...inputProps, ...outputProps]) {
1048
+ const rawType = p16.type.trim();
1049
1049
  const baseType = rawType.replace(/\[\]$/, "").trim();
1050
1050
  if (!primitiveTypes.has(baseType) && /^[A-Z][A-Za-z0-9_]*$/.test(baseType) && !dependencies.includes(baseType)) {
1051
1051
  domainTypesToImport.add(baseType);
1052
1052
  }
1053
1053
  }
1054
- const formattedInputProps = inputProps.map((p17) => ({
1055
- name: p17.name,
1056
- optional: p17.optional,
1057
- type: p17.optional && !p17.type.includes("undefined") ? `${p17.type} | undefined` : p17.type
1054
+ const formattedInputProps = inputProps.map((p16) => ({
1055
+ name: p16.name,
1056
+ optional: p16.optional,
1057
+ type: p16.optional && !p16.type.includes("undefined") ? `${p16.type} | undefined` : p16.type
1058
1058
  }));
1059
- const formattedOutputProps = outputProps.map((p17) => ({
1060
- name: p17.name,
1061
- optional: p17.optional,
1062
- type: p17.optional && !p17.type.includes("undefined") ? `${p17.type} | undefined` : p17.type
1059
+ const formattedOutputProps = outputProps.map((p16) => ({
1060
+ name: p16.name,
1061
+ optional: p16.optional,
1062
+ type: p16.optional && !p16.type.includes("undefined") ? `${p16.type} | undefined` : p16.type
1063
1063
  }));
1064
1064
  const formattedDeps = dependencies.map((dep) => ({
1065
1065
  key: toCamelCase(dep),
@@ -1246,7 +1246,7 @@ function generateHttpHandler(options) {
1246
1246
  const pxDir = path2.join(resolveFeaturesDir(projectRoot), options.feature, "pxExpress");
1247
1247
  const handlersDir = path2.join(pxDir, "handlers");
1248
1248
  const pxIndexPath = path2.join(pxDir, "index.ts");
1249
- if (!fs12.existsSync(pxIndexPath)) {
1249
+ if (!fs9.existsSync(pxIndexPath)) {
1250
1250
  const featurePath = options.routePrefix || `/${options.feature.toLowerCase()}`;
1251
1251
  const pxIndexContent = renderTemplate(expressIndexTemplate, {
1252
1252
  routePath: featurePath
@@ -1283,8 +1283,8 @@ function updateOrGenerateDiProvider(featureDir, featureName, bindings = [], opti
1283
1283
  const providerPath = path2.join(featureDir, "diProvider.ts");
1284
1284
  const pascalFeature = toPascalCase(featureName);
1285
1285
  const providerModuleName = `${pascalFeature}Provider`;
1286
- if (fs12.existsSync(providerPath) && !options.overwrite) {
1287
- let content = fs12.readFileSync(providerPath, "utf-8");
1286
+ if (fs9.existsSync(providerPath) && !options.overwrite) {
1287
+ let content = fs9.readFileSync(providerPath, "utf-8");
1288
1288
  content = content.replace(/\n*export\s+const\s+ScaffoldProvider\s*=[^;]+;?/g, "");
1289
1289
  for (const b of bindings) {
1290
1290
  const ifaceImp = b.ifaceImportPath || `./domain/${b.ifaceName}.js`;
@@ -1730,23 +1730,23 @@ var PromptCancelledError = class extends Error {
1730
1730
  }
1731
1731
  };
1732
1732
  function handleCancel(result) {
1733
- if (p15.isCancel(result)) {
1734
- p15.cancel("Operation cancelled.");
1733
+ if (p3.isCancel(result)) {
1734
+ p3.cancel("Operation cancelled.");
1735
1735
  throw new PromptCancelledError();
1736
1736
  }
1737
1737
  return result;
1738
1738
  }
1739
1739
  function printBanner() {
1740
1740
  console.log("");
1741
- p15.intro(pc15.bgCyan(pc15.black(" @solid-stack/mason ")));
1741
+ p3.intro(pc14.bgCyan(pc14.black(" @solid-stack/mason ")));
1742
1742
  }
1743
1743
  async function promptProperties(options = {}) {
1744
1744
  const properties = options.defaults ? [...options.defaults] : [];
1745
1745
  if (properties.length > 0) {
1746
- const summary = properties.map((p17) => `${p17.name}: ${p17.type}${p17.optional ? "?" : ""}`).join(", ");
1747
- p15.log.info(pc15.dim(`Pre-configured fields: ${summary}`));
1746
+ const summary = properties.map((p16) => `${p16.name}: ${p16.type}${p16.optional ? "?" : ""}`).join(", ");
1747
+ p3.log.info(pc14.dim(`Pre-configured fields: ${summary}`));
1748
1748
  const addMore = handleCancel(
1749
- await p15.confirm({
1749
+ await p3.confirm({
1750
1750
  message: "Would you like to add custom fields/properties?",
1751
1751
  initialValue: false
1752
1752
  })
@@ -1755,10 +1755,10 @@ async function promptProperties(options = {}) {
1755
1755
  return properties;
1756
1756
  }
1757
1757
  }
1758
- p15.log.info(pc15.cyan("Enter properties (leave name blank when finished):"));
1758
+ p3.log.info(pc14.cyan("Enter properties (leave name blank when finished):"));
1759
1759
  while (true) {
1760
1760
  const name = handleCancel(
1761
- await p15.text({
1761
+ await p3.text({
1762
1762
  message: "Property name (or press Enter to finish):",
1763
1763
  placeholder: "e.g. title, email, status"
1764
1764
  })
@@ -1767,7 +1767,7 @@ async function promptProperties(options = {}) {
1767
1767
  break;
1768
1768
  }
1769
1769
  const type = handleCancel(
1770
- await p15.select({
1770
+ await p3.select({
1771
1771
  message: `Type for property "${name.trim()}":`,
1772
1772
  options: [
1773
1773
  { value: "string", label: "string" },
@@ -1784,7 +1784,7 @@ async function promptProperties(options = {}) {
1784
1784
  let finalType = type;
1785
1785
  if (type === "custom") {
1786
1786
  finalType = handleCancel(
1787
- await p15.text({
1787
+ await p3.text({
1788
1788
  message: `Enter custom type for "${name.trim()}":`,
1789
1789
  placeholder: "e.g. UserRole, string | null",
1790
1790
  validate: (val) => val && val.trim() ? void 0 : "Type cannot be empty"
@@ -1792,7 +1792,7 @@ async function promptProperties(options = {}) {
1792
1792
  );
1793
1793
  }
1794
1794
  const optional = handleCancel(
1795
- await p15.confirm({
1795
+ await p3.confirm({
1796
1796
  message: `Is "${name.trim()}" optional?`,
1797
1797
  initialValue: false
1798
1798
  })
@@ -1802,8 +1802,8 @@ async function promptProperties(options = {}) {
1802
1802
  type: finalType.trim(),
1803
1803
  optional
1804
1804
  });
1805
- p15.log.success(
1806
- pc15.green(`Added: ${name.trim()}${optional ? "?" : ""}: ${finalType.trim()}`)
1805
+ p3.log.success(
1806
+ pc14.green(`Added: ${name.trim()}${optional ? "?" : ""}: ${finalType.trim()}`)
1807
1807
  );
1808
1808
  }
1809
1809
  return properties;
@@ -1819,7 +1819,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1819
1819
  }
1820
1820
  if (!name) {
1821
1821
  name = handleCancel(
1822
- await p15.text({
1822
+ await p3.text({
1823
1823
  message: "What is the feature name?",
1824
1824
  placeholder: "e.g. users, auth, orders, billing",
1825
1825
  validate: (val) => {
@@ -1835,7 +1835,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1835
1835
  let targetDirRel = defaultDir;
1836
1836
  if (!flags.yes && !flags.target && !flags.dest) {
1837
1837
  targetDirRel = handleCancel(
1838
- await p15.text({
1838
+ await p3.text({
1839
1839
  message: "Target directory for the feature:",
1840
1840
  initialValue: defaultDir,
1841
1841
  defaultValue: defaultDir
@@ -1857,14 +1857,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1857
1857
  const customUseCases = [];
1858
1858
  if (!flags.yes) {
1859
1859
  includeExpress = handleCancel(
1860
- await p15.confirm({
1860
+ await p3.confirm({
1861
1861
  message: "Include Express Presentation layer (pxExpress routes & handlers)?",
1862
1862
  initialValue: true
1863
1863
  })
1864
1864
  );
1865
1865
  if (includeExpress) {
1866
1866
  routePath = handleCancel(
1867
- await p15.text({
1867
+ await p3.text({
1868
1868
  message: "Express route prefix:",
1869
1869
  initialValue: `/${normalizedName}`,
1870
1870
  defaultValue: `/${normalizedName}`
@@ -1872,14 +1872,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1872
1872
  ).trim();
1873
1873
  }
1874
1874
  includeDomain = handleCancel(
1875
- await p15.confirm({
1875
+ await p3.confirm({
1876
1876
  message: "Include Domain Entity/Entities?",
1877
1877
  initialValue: true
1878
1878
  })
1879
1879
  );
1880
1880
  if (includeDomain) {
1881
1881
  const domainInput = handleCancel(
1882
- await p15.text({
1882
+ await p3.text({
1883
1883
  message: "Domain entity name(s) (comma-separated):",
1884
1884
  initialValue: defaultEntity,
1885
1885
  defaultValue: defaultEntity,
@@ -1898,21 +1898,21 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1898
1898
  entityNames = [defaultEntity];
1899
1899
  }
1900
1900
  includeInterface = handleCancel(
1901
- await p15.confirm({
1901
+ await p3.confirm({
1902
1902
  message: `Include Domain Repository interface(s) for ${entityNames.join(", ")}?`,
1903
1903
  initialValue: true
1904
1904
  })
1905
1905
  );
1906
1906
  if (includeInterface) {
1907
1907
  includeInfra = handleCancel(
1908
- await p15.confirm({
1908
+ await p3.confirm({
1909
1909
  message: `Include Infrastructure Stub implementation(s) for ${entityNames.join(", ")}?`,
1910
1910
  initialValue: true
1911
1911
  })
1912
1912
  );
1913
1913
  }
1914
1914
  includeUseCase = handleCancel(
1915
- await p15.confirm({
1915
+ await p3.confirm({
1916
1916
  message: "Include Domain Use Cases?",
1917
1917
  initialValue: true
1918
1918
  })
@@ -1926,7 +1926,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1926
1926
  { value: "delete", label: "Delete (Delete<Entity>)", hint: "DELETE /:id" }
1927
1927
  ];
1928
1928
  crudOperations = handleCancel(
1929
- await p15.multiselect({
1929
+ await p3.multiselect({
1930
1930
  message: "Select standard CRUD use cases to generate:",
1931
1931
  options: crudChoices,
1932
1932
  initialValues: ["create", "read", "list", "update", "delete"],
@@ -1934,13 +1934,13 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1934
1934
  })
1935
1935
  );
1936
1936
  includeTests = handleCancel(
1937
- await p15.confirm({
1937
+ await p3.confirm({
1938
1938
  message: "Generate Vitest unit tests for use cases?",
1939
1939
  initialValue: true
1940
1940
  })
1941
1941
  );
1942
1942
  const wantCustom = handleCancel(
1943
- await p15.confirm({
1943
+ await p3.confirm({
1944
1944
  message: "Do you want to add any custom use cases to this feature?",
1945
1945
  initialValue: false
1946
1946
  })
@@ -1950,7 +1950,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1950
1950
  const availableIfaces = entityNames.map((e) => `I${e}Repository`);
1951
1951
  while (addMore) {
1952
1952
  const customName = handleCancel(
1953
- await p15.text({
1953
+ await p3.text({
1954
1954
  message: "Custom Use Case name:",
1955
1955
  placeholder: "e.g. ResetPassword, VerifyEmail, AssignRole",
1956
1956
  validate: (v) => v && v.trim() ? void 0 : "Use Case name cannot be empty"
@@ -1960,7 +1960,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1960
1960
  let selectedDeps = [];
1961
1961
  if (availableIfaces.length > 0) {
1962
1962
  selectedDeps = handleCancel(
1963
- await p15.multiselect({
1963
+ await p3.multiselect({
1964
1964
  message: `Select domain interfaces to inject into ${customUcName}:`,
1965
1965
  options: availableIfaces.map((i) => ({ value: i, label: i })),
1966
1966
  required: false
@@ -1969,7 +1969,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1969
1969
  }
1970
1970
  let customInputProps = [];
1971
1971
  const hasInput = handleCancel(
1972
- await p15.confirm({
1972
+ await p3.confirm({
1973
1973
  message: `Does ${customUcName} accept input arguments?`,
1974
1974
  initialValue: true
1975
1975
  })
@@ -1980,7 +1980,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1980
1980
  }
1981
1981
  let customOutputProps = [];
1982
1982
  const hasCustomOutput = handleCancel(
1983
- await p15.confirm({
1983
+ await p3.confirm({
1984
1984
  message: `Does ${customUcName} return custom output data?`,
1985
1985
  initialValue: false
1986
1986
  })
@@ -1990,7 +1990,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
1990
1990
  });
1991
1991
  }
1992
1992
  const customIncludeTest = handleCancel(
1993
- await p15.confirm({
1993
+ await p3.confirm({
1994
1994
  message: `Generate Vitest unit test for ${customUcName}?`,
1995
1995
  initialValue: true
1996
1996
  })
@@ -2000,14 +2000,14 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2000
2000
  let customHttpPath = `/${toKebabCase(customUcName)}`;
2001
2001
  if (includeExpress) {
2002
2002
  customCreateHttp = handleCancel(
2003
- await p15.confirm({
2003
+ await p3.confirm({
2004
2004
  message: `Generate a matching ExpressRoute HTTP handler for ${customUcName}?`,
2005
2005
  initialValue: true
2006
2006
  })
2007
2007
  );
2008
2008
  if (customCreateHttp) {
2009
2009
  customHttpMethod = handleCancel(
2010
- await p15.select({
2010
+ await p3.select({
2011
2011
  message: "HTTP method for route:",
2012
2012
  options: [
2013
2013
  { value: "post", label: "POST" },
@@ -2020,7 +2020,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2020
2020
  })
2021
2021
  );
2022
2022
  customHttpPath = handleCancel(
2023
- await p15.text({
2023
+ await p3.text({
2024
2024
  message: "Route subpath (relative to feature prefix):",
2025
2025
  initialValue: `/${toKebabCase(customUcName)}`,
2026
2026
  defaultValue: `/${toKebabCase(customUcName)}`
@@ -2041,7 +2041,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2041
2041
  validationFields: customInputProps
2042
2042
  });
2043
2043
  addMore = handleCancel(
2044
- await p15.confirm({
2044
+ await p3.confirm({
2045
2045
  message: "Add another custom use case?",
2046
2046
  initialValue: false
2047
2047
  })
@@ -2050,7 +2050,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2050
2050
  }
2051
2051
  }
2052
2052
  includeDiProvider = handleCancel(
2053
- await p15.confirm({
2053
+ await p3.confirm({
2054
2054
  message: "Generate / update feature DI provider (diProvider.ts)?",
2055
2055
  initialValue: true
2056
2056
  })
@@ -2062,8 +2062,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2062
2062
  entityNames = [defaultEntity];
2063
2063
  }
2064
2064
  }
2065
- const s = p15.spinner();
2066
- s.start(`Generating feature '${pc15.cyan(normalizedName)}'...`);
2065
+ const s = p3.spinner();
2066
+ s.start(`Generating feature '${pc14.cyan(normalizedName)}'...`);
2067
2067
  const options = {
2068
2068
  name: normalizedName,
2069
2069
  projectRoot,
@@ -2085,7 +2085,7 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2085
2085
  const files = generateFeature(options);
2086
2086
  if (isRegistry) {
2087
2087
  const registryPath = path2.join(targetDir, "registry.json");
2088
- if (!fs12.existsSync(registryPath)) {
2088
+ if (!fs9.existsSync(registryPath)) {
2089
2089
  const manifest = {
2090
2090
  name: toKebabCase(normalizedName),
2091
2091
  type: "feature",
@@ -2109,8 +2109,8 @@ async function runFeatureCommand(featureNameArg, flags = {}) {
2109
2109
  }
2110
2110
  s.stop("Feature scaffolded successfully!");
2111
2111
  printGeneratedFiles(files, options.dryRun);
2112
- p15.outro(
2113
- pc15.green(
2112
+ p3.outro(
2113
+ pc14.green(
2114
2114
  `\u2713 Feature '${normalizedName}' initialized in ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2115
2115
  )
2116
2116
  );
@@ -2224,7 +2224,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2224
2224
  }
2225
2225
  if (!name) {
2226
2226
  name = handleCancel(
2227
- await p15.text({
2227
+ await p3.text({
2228
2228
  message: "What is the shared module name?",
2229
2229
  placeholder: "e.g. hasher, time, uuid, cache, logger",
2230
2230
  validate: (val) => {
@@ -2240,7 +2240,7 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2240
2240
  let targetDirRel = defaultDir;
2241
2241
  if (!flags.yes && !flags.target && !flags.dest) {
2242
2242
  targetDirRel = handleCancel(
2243
- await p15.text({
2243
+ await p3.text({
2244
2244
  message: "Target directory for the shared module:",
2245
2245
  initialValue: defaultDir,
2246
2246
  defaultValue: defaultDir
@@ -2252,21 +2252,21 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2252
2252
  let includeStub = true;
2253
2253
  if (!flags.yes) {
2254
2254
  description = handleCancel(
2255
- await p15.text({
2255
+ await p3.text({
2256
2256
  message: "Module description (optional):",
2257
2257
  placeholder: "e.g. In-memory caching and Redis port abstraction",
2258
2258
  initialValue: ""
2259
2259
  })
2260
2260
  ).trim();
2261
2261
  includeStub = handleCancel(
2262
- await p15.confirm({
2262
+ await p3.confirm({
2263
2263
  message: "Include stub implementation in infrastructure/?",
2264
2264
  initialValue: true
2265
2265
  })
2266
2266
  );
2267
2267
  }
2268
- const s = p15.spinner();
2269
- s.start(`Generating shared module '${pc15.cyan(normalizedName)}'...`);
2268
+ const s = p3.spinner();
2269
+ s.start(`Generating shared module '${pc14.cyan(normalizedName)}'...`);
2270
2270
  const files = generateShared({
2271
2271
  name: normalizedName,
2272
2272
  description,
@@ -2279,8 +2279,8 @@ async function runSharedCommand(sharedNameArg, flags = {}) {
2279
2279
  });
2280
2280
  s.stop("Shared module generated successfully!");
2281
2281
  printGeneratedFiles(files, Boolean(flags.dryRun));
2282
- p15.outro(
2283
- pc15.green(
2282
+ p3.outro(
2283
+ pc14.green(
2284
2284
  `\u2713 Shared module '${normalizedName}' initialized in ${path2.relative(projectRoot, targetDir)} (uncommitted, unregistered)`
2285
2285
  )
2286
2286
  );
@@ -2294,14 +2294,14 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2294
2294
  const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
2295
2295
  featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
2296
2296
  const selected = handleCancel(
2297
- await p15.select({
2297
+ await p3.select({
2298
2298
  message: "Select target feature:",
2299
2299
  options: featureOptions
2300
2300
  })
2301
2301
  );
2302
2302
  if (selected === "__custom__") {
2303
2303
  feature = handleCancel(
2304
- await p15.text({
2304
+ await p3.text({
2305
2305
  message: "Enter feature name:",
2306
2306
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2307
2307
  })
@@ -2311,7 +2311,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2311
2311
  }
2312
2312
  } else {
2313
2313
  feature = handleCancel(
2314
- await p15.text({
2314
+ await p3.text({
2315
2315
  message: "Enter target feature name:",
2316
2316
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2317
2317
  })
@@ -2322,7 +2322,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2322
2322
  let name = useCaseNameArg?.trim();
2323
2323
  if (!name) {
2324
2324
  name = handleCancel(
2325
- await p15.text({
2325
+ await p3.text({
2326
2326
  message: "Use Case name:",
2327
2327
  placeholder: "e.g. CreateUser, GetUser, CancelOrder",
2328
2328
  validate: (v) => v && v.trim() ? void 0 : "Use Case name cannot be empty"
@@ -2338,7 +2338,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2338
2338
  label: i.name
2339
2339
  }));
2340
2340
  selectedDeps = handleCancel(
2341
- await p15.multiselect({
2341
+ await p3.multiselect({
2342
2342
  message: "Select domain interfaces to inject into use case:",
2343
2343
  options: multiOptions,
2344
2344
  required: false
@@ -2353,7 +2353,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2353
2353
  let httpPath = "/";
2354
2354
  if (!flags.yes) {
2355
2355
  const hasInput = handleCancel(
2356
- await p15.confirm({
2356
+ await p3.confirm({
2357
2357
  message: "Does this use case accept input arguments?",
2358
2358
  initialValue: true
2359
2359
  })
@@ -2363,7 +2363,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2363
2363
  });
2364
2364
  }
2365
2365
  const hasCustomOutput = handleCancel(
2366
- await p15.confirm({
2366
+ await p3.confirm({
2367
2367
  message: "Does this use case return custom output data?",
2368
2368
  initialValue: false
2369
2369
  })
@@ -2373,20 +2373,20 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2373
2373
  });
2374
2374
  }
2375
2375
  includeTest = handleCancel(
2376
- await p15.confirm({
2376
+ await p3.confirm({
2377
2377
  message: "Generate Vitest unit test skeleton (.test.ts)?",
2378
2378
  initialValue: true
2379
2379
  })
2380
2380
  );
2381
2381
  createHttp = handleCancel(
2382
- await p15.confirm({
2382
+ await p3.confirm({
2383
2383
  message: "Generate a matching ExpressRoute HTTP handler?",
2384
2384
  initialValue: false
2385
2385
  })
2386
2386
  );
2387
2387
  if (createHttp) {
2388
2388
  httpMethod = handleCancel(
2389
- await p15.select({
2389
+ await p3.select({
2390
2390
  message: "HTTP method for route:",
2391
2391
  options: [
2392
2392
  { value: "post", label: "POST" },
@@ -2399,7 +2399,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2399
2399
  })
2400
2400
  );
2401
2401
  httpPath = handleCancel(
2402
- await p15.text({
2402
+ await p3.text({
2403
2403
  message: "Route subpath (relative to feature prefix):",
2404
2404
  initialValue: "/",
2405
2405
  defaultValue: "/"
@@ -2407,8 +2407,8 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2407
2407
  ).trim();
2408
2408
  }
2409
2409
  }
2410
- const s = p15.spinner();
2411
- s.start(`Generating use case '${pc15.cyan(ucName)}'...`);
2410
+ const s = p3.spinner();
2411
+ s.start(`Generating use case '${pc14.cyan(ucName)}'...`);
2412
2412
  const options = {
2413
2413
  name: ucName,
2414
2414
  feature,
@@ -2440,7 +2440,7 @@ async function runUseCaseCommand(useCaseNameArg, flags = {}) {
2440
2440
  }
2441
2441
  s.stop("Use case generated successfully!");
2442
2442
  printGeneratedFiles(files, options.dryRun);
2443
- p15.outro(pc15.green(`Use case '${ucName}' created in feature '${feature}'!`));
2443
+ p3.outro(pc14.green(`Use case '${ucName}' created in feature '${feature}'!`));
2444
2444
  }
2445
2445
  async function runDomainCommand(domainNameArg, flags = {}) {
2446
2446
  const projectRoot = findProjectRoot();
@@ -2451,14 +2451,14 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2451
2451
  const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
2452
2452
  featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
2453
2453
  const selected = handleCancel(
2454
- await p15.select({
2454
+ await p3.select({
2455
2455
  message: "Select target feature:",
2456
2456
  options: featureOptions
2457
2457
  })
2458
2458
  );
2459
2459
  if (selected === "__custom__") {
2460
2460
  feature = handleCancel(
2461
- await p15.text({
2461
+ await p3.text({
2462
2462
  message: "Enter feature name:",
2463
2463
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2464
2464
  })
@@ -2468,7 +2468,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2468
2468
  }
2469
2469
  } else {
2470
2470
  feature = handleCancel(
2471
- await p15.text({
2471
+ await p3.text({
2472
2472
  message: "Enter target feature name:",
2473
2473
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2474
2474
  })
@@ -2479,7 +2479,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2479
2479
  let name = domainNameArg?.trim();
2480
2480
  if (!name) {
2481
2481
  name = handleCancel(
2482
- await p15.text({
2482
+ await p3.text({
2483
2483
  message: "Domain model / entity name:",
2484
2484
  placeholder: "e.g. User, Order, Product, Address",
2485
2485
  validate: (v) => v && v.trim() ? void 0 : "Domain name cannot be empty"
@@ -2491,7 +2491,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2491
2491
  let properties = [];
2492
2492
  if (!flags.yes) {
2493
2493
  kind = handleCancel(
2494
- await p15.select({
2494
+ await p3.select({
2495
2495
  message: "Select domain model type:",
2496
2496
  options: [
2497
2497
  { value: "interface", label: "TypeScript Interface (pure data structure)" },
@@ -2510,8 +2510,8 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2510
2510
  defaults: kind === "valueObject" ? [{ name: "value", type: "string" }] : defaultProps
2511
2511
  });
2512
2512
  }
2513
- const s = p15.spinner();
2514
- s.start(`Generating domain model '${pc15.cyan(entityName)}'...`);
2513
+ const s = p3.spinner();
2514
+ s.start(`Generating domain model '${pc14.cyan(entityName)}'...`);
2515
2515
  const options = {
2516
2516
  name: entityName,
2517
2517
  feature,
@@ -2524,7 +2524,7 @@ async function runDomainCommand(domainNameArg, flags = {}) {
2524
2524
  const file = generateDomain(options);
2525
2525
  s.stop("Domain model generated successfully!");
2526
2526
  printGeneratedFiles([file], options.dryRun);
2527
- p15.outro(pc15.green(`Domain model '${entityName}' created in feature '${feature}'!`));
2527
+ p3.outro(pc14.green(`Domain model '${entityName}' created in feature '${feature}'!`));
2528
2528
  }
2529
2529
  async function runInfrastructureCommand(classNameArg, flags = {}) {
2530
2530
  const projectRoot = findProjectRoot();
@@ -2533,7 +2533,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2533
2533
  let feature = flags.feature?.trim();
2534
2534
  if (!flags.yes && !flags.global && !flags.feature) {
2535
2535
  scope = handleCancel(
2536
- await p15.select({
2536
+ await p3.select({
2537
2537
  message: "Where should this infrastructure implementation be placed?",
2538
2538
  options: [
2539
2539
  { value: "feature", label: "Feature-level (features/<feature>/infrastructure)" },
@@ -2548,14 +2548,14 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2548
2548
  const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
2549
2549
  featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
2550
2550
  const selected = handleCancel(
2551
- await p15.select({
2551
+ await p3.select({
2552
2552
  message: "Select target feature:",
2553
2553
  options: featureOptions
2554
2554
  })
2555
2555
  );
2556
2556
  if (selected === "__custom__") {
2557
2557
  feature = handleCancel(
2558
- await p15.text({
2558
+ await p3.text({
2559
2559
  message: "Enter feature name:",
2560
2560
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2561
2561
  })
@@ -2565,7 +2565,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2565
2565
  }
2566
2566
  } else {
2567
2567
  feature = handleCancel(
2568
- await p15.text({
2568
+ await p3.text({
2569
2569
  message: "Enter target feature name:",
2570
2570
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2571
2571
  })
@@ -2578,7 +2578,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2578
2578
  let name = classNameArg?.trim();
2579
2579
  if (!name) {
2580
2580
  name = handleCancel(
2581
- await p15.text({
2581
+ await p3.text({
2582
2582
  message: "Infrastructure class name:",
2583
2583
  placeholder: "e.g. StubUserRepository, PostgresUserRepository, S3FileStorage",
2584
2584
  validate: (v) => v && v.trim() ? void 0 : "Class name cannot be empty"
@@ -2597,7 +2597,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2597
2597
  (i) => className.toLowerCase().includes(removeInterfacePrefix(i.name).toLowerCase())
2598
2598
  );
2599
2599
  const ifaceChoice = handleCancel(
2600
- await p15.select({
2600
+ await p3.select({
2601
2601
  message: "Does this class implement a domain interface or abstract class?",
2602
2602
  options: [
2603
2603
  ...interfaces.map((i) => ({ value: i.name, label: i.name })),
@@ -2609,7 +2609,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2609
2609
  );
2610
2610
  if (ifaceChoice === "__custom__") {
2611
2611
  implementsInterface = handleCancel(
2612
- await p15.text({
2612
+ await p3.text({
2613
2613
  message: "Enter interface or abstract class name:",
2614
2614
  placeholder: "e.g. IUserRepository, BaseStorageAdapter",
2615
2615
  validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
@@ -2620,14 +2620,14 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2620
2620
  }
2621
2621
  } else {
2622
2622
  const wantImpl = handleCancel(
2623
- await p15.confirm({
2623
+ await p3.confirm({
2624
2624
  message: "Does this class implement a domain interface or abstract class?",
2625
2625
  initialValue: false
2626
2626
  })
2627
2627
  );
2628
2628
  if (wantImpl) {
2629
2629
  implementsInterface = handleCancel(
2630
- await p15.text({
2630
+ await p3.text({
2631
2631
  message: "Enter interface or abstract class name:",
2632
2632
  placeholder: "e.g. IUserRepository, BaseStorageAdapter",
2633
2633
  validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
@@ -2647,7 +2647,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2647
2647
  const allInterfaces = listDomainInterfaces(projectRoot);
2648
2648
  if (allInterfaces.length > 0) {
2649
2649
  const ifaceChoice = handleCancel(
2650
- await p15.select({
2650
+ await p3.select({
2651
2651
  message: "Does this class implement an interface or abstract class?",
2652
2652
  options: [
2653
2653
  ...allInterfaces.map((i) => ({ value: i.name, label: `${i.name} (${i.feature})` })),
@@ -2659,7 +2659,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2659
2659
  );
2660
2660
  if (ifaceChoice === "__custom__") {
2661
2661
  implementsInterface = handleCancel(
2662
- await p15.text({
2662
+ await p3.text({
2663
2663
  message: "Enter interface or abstract class name:",
2664
2664
  placeholder: "e.g. IAuthRepository",
2665
2665
  validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
@@ -2672,7 +2672,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2672
2672
  }
2673
2673
  if (!flags.yes && !flags.kind) {
2674
2674
  kind = handleCancel(
2675
- await p15.select({
2675
+ await p3.select({
2676
2676
  message: "Select implementation kind:",
2677
2677
  options: [
2678
2678
  { value: "stub", label: "In-Memory Stub (with in-memory store and test helper methods)" },
@@ -2683,7 +2683,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2683
2683
  );
2684
2684
  if (scope === "feature" && feature && implementsInterface) {
2685
2685
  registerInProvider = handleCancel(
2686
- await p15.confirm({
2686
+ await p3.confirm({
2687
2687
  message: "Register this implementation in feature diProvider.ts?",
2688
2688
  initialValue: true
2689
2689
  })
@@ -2692,8 +2692,8 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2692
2692
  } else if (flags.yes && scope === "feature" && feature && implementsInterface) {
2693
2693
  registerInProvider = !flags.noProvider;
2694
2694
  }
2695
- const s = p15.spinner();
2696
- s.start(`Generating infrastructure class '${pc15.cyan(className)}'...`);
2695
+ const s = p3.spinner();
2696
+ s.start(`Generating infrastructure class '${pc14.cyan(className)}'...`);
2697
2697
  const files = [];
2698
2698
  const options = {
2699
2699
  name: className,
@@ -2728,7 +2728,7 @@ async function runInfrastructureCommand(classNameArg, flags = {}) {
2728
2728
  }
2729
2729
  s.stop("Infrastructure class generated successfully!");
2730
2730
  printGeneratedFiles(files, options.dryRun);
2731
- p15.outro(pc15.green(`Infrastructure class '${className}' created!`));
2731
+ p3.outro(pc14.green(`Infrastructure class '${className}' created!`));
2732
2732
  }
2733
2733
  async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2734
2734
  const projectRoot = findProjectRoot();
@@ -2739,14 +2739,14 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2739
2739
  const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
2740
2740
  featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
2741
2741
  const selected = handleCancel(
2742
- await p15.select({
2742
+ await p3.select({
2743
2743
  message: "Select target feature:",
2744
2744
  options: featureOptions
2745
2745
  })
2746
2746
  );
2747
2747
  if (selected === "__custom__") {
2748
2748
  feature = handleCancel(
2749
- await p15.text({
2749
+ await p3.text({
2750
2750
  message: "Enter feature name:",
2751
2751
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2752
2752
  })
@@ -2756,7 +2756,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2756
2756
  }
2757
2757
  } else {
2758
2758
  feature = handleCancel(
2759
- await p15.text({
2759
+ await p3.text({
2760
2760
  message: "Enter target feature name:",
2761
2761
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2762
2762
  })
@@ -2767,7 +2767,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2767
2767
  let name = interfaceNameArg?.trim();
2768
2768
  if (!name) {
2769
2769
  name = handleCancel(
2770
- await p15.text({
2770
+ await p3.text({
2771
2771
  message: "Domain interface name:",
2772
2772
  placeholder: "e.g. IUserRepository, IPaymentService",
2773
2773
  validate: (v) => v && v.trim() ? void 0 : "Interface name cannot be empty"
@@ -2785,7 +2785,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2785
2785
  if (!flags.yes) {
2786
2786
  if (existingEntities.length > 0) {
2787
2787
  const selectedEntity = handleCancel(
2788
- await p15.select({
2788
+ await p3.select({
2789
2789
  message: "Select domain entity associated with this interface:",
2790
2790
  options: [
2791
2791
  ...existingEntities.map((e) => ({ value: e.name, label: e.name })),
@@ -2796,7 +2796,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2796
2796
  );
2797
2797
  if (selectedEntity === "__custom__") {
2798
2798
  entityName = handleCancel(
2799
- await p15.text({
2799
+ await p3.text({
2800
2800
  message: "Enter entity name:",
2801
2801
  defaultValue: removeInterfacePrefix(ifaceName).replace(/Repository$|Service$/, "")
2802
2802
  })
@@ -2806,7 +2806,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2806
2806
  }
2807
2807
  }
2808
2808
  kind = handleCancel(
2809
- await p15.select({
2809
+ await p3.select({
2810
2810
  message: "Interface definition style:",
2811
2811
  options: [
2812
2812
  { value: "abstractClass", label: "Abstract Class (Recommended - acts as DI token & type)" },
@@ -2816,7 +2816,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2816
2816
  })
2817
2817
  );
2818
2818
  methodsPreset = handleCancel(
2819
- await p15.select({
2819
+ await p3.select({
2820
2820
  message: "Method signature preset:",
2821
2821
  options: [
2822
2822
  { value: "crud", label: "Standard CRUD (GetById, List, Create, Update, Delete)" },
@@ -2826,22 +2826,22 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2826
2826
  })
2827
2827
  );
2828
2828
  generateStub = handleCancel(
2829
- await p15.confirm({
2829
+ await p3.confirm({
2830
2830
  message: "Auto-generate Infrastructure Stub implementation?",
2831
2831
  initialValue: true
2832
2832
  })
2833
2833
  );
2834
2834
  if (generateStub) {
2835
2835
  registerInProvider = handleCancel(
2836
- await p15.confirm({
2836
+ await p3.confirm({
2837
2837
  message: "Auto-register interface & stub in feature diProvider.ts?",
2838
2838
  initialValue: true
2839
2839
  })
2840
2840
  );
2841
2841
  }
2842
2842
  }
2843
- const s = p15.spinner();
2844
- s.start(`Generating interface '${pc15.cyan(ifaceName)}'...`);
2843
+ const s = p3.spinner();
2844
+ s.start(`Generating interface '${pc14.cyan(ifaceName)}'...`);
2845
2845
  const files = [];
2846
2846
  const options = {
2847
2847
  name: ifaceName,
@@ -2890,7 +2890,7 @@ async function runInterfaceCommand(interfaceNameArg, flags = {}) {
2890
2890
  }
2891
2891
  s.stop("Interface generated successfully!");
2892
2892
  printGeneratedFiles(files, options.dryRun);
2893
- p15.outro(pc15.green(`Interface '${ifaceName}' created in feature '${feature}'!`));
2893
+ p3.outro(pc14.green(`Interface '${ifaceName}' created in feature '${feature}'!`));
2894
2894
  }
2895
2895
  async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2896
2896
  const projectRoot = findProjectRoot();
@@ -2901,14 +2901,14 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2901
2901
  const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
2902
2902
  featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
2903
2903
  const selected = handleCancel(
2904
- await p15.select({
2904
+ await p3.select({
2905
2905
  message: "Select target feature:",
2906
2906
  options: featureOptions
2907
2907
  })
2908
2908
  );
2909
2909
  if (selected === "__custom__") {
2910
2910
  feature = handleCancel(
2911
- await p15.text({
2911
+ await p3.text({
2912
2912
  message: "Enter feature name:",
2913
2913
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2914
2914
  })
@@ -2918,7 +2918,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2918
2918
  }
2919
2919
  } else {
2920
2920
  feature = handleCancel(
2921
- await p15.text({
2921
+ await p3.text({
2922
2922
  message: "Enter target feature name:",
2923
2923
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
2924
2924
  })
@@ -2929,7 +2929,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2929
2929
  let name = handlerNameArg?.trim();
2930
2930
  if (!name) {
2931
2931
  name = handleCancel(
2932
- await p15.text({
2932
+ await p3.text({
2933
2933
  message: "HTTP Route Handler class name:",
2934
2934
  placeholder: "e.g. CreateUserHttp, GetUserHttp, HealthHttp",
2935
2935
  validate: (v) => v && v.trim() ? void 0 : "Handler name cannot be empty"
@@ -2948,7 +2948,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2948
2948
  let validationFields = [];
2949
2949
  if (!flags.yes) {
2950
2950
  method = handleCancel(
2951
- await p15.select({
2951
+ await p3.select({
2952
2952
  message: "HTTP Method:",
2953
2953
  options: [
2954
2954
  { value: "get", label: "GET" },
@@ -2962,7 +2962,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2962
2962
  );
2963
2963
  const defaultPath = method === "get" ? "/" : "/";
2964
2964
  subPath = handleCancel(
2965
- await p15.text({
2965
+ await p3.text({
2966
2966
  message: "Route subpath (relative to feature prefix):",
2967
2967
  initialValue: defaultPath,
2968
2968
  defaultValue: defaultPath
@@ -2973,7 +2973,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2973
2973
  const ucOptions = useCases.map((u) => ({ value: u.name, label: u.name }));
2974
2974
  ucOptions.push({ value: "__none__", label: "None / Standalone Handler" });
2975
2975
  const chosenUc = handleCancel(
2976
- await p15.select({
2976
+ await p3.select({
2977
2977
  message: "Connect this handler to a domain Use Case?",
2978
2978
  options: ucOptions,
2979
2979
  initialValue: ucOptions[0]?.value
@@ -2984,7 +2984,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2984
2984
  }
2985
2985
  }
2986
2986
  includeValidation = handleCancel(
2987
- await p15.confirm({
2987
+ await p3.confirm({
2988
2988
  message: "Include Zod inbound request validation?",
2989
2989
  initialValue: method !== "delete"
2990
2990
  })
@@ -2992,7 +2992,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
2992
2992
  if (includeValidation) {
2993
2993
  const defaultSource = method === "get" ? "query" : "body";
2994
2994
  validationSource = handleCancel(
2995
- await p15.select({
2995
+ await p3.select({
2996
2996
  message: "Validation data source:",
2997
2997
  options: [
2998
2998
  { value: "body", label: "req.body (for POST / PUT / PATCH payloads)" },
@@ -3006,8 +3006,8 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
3006
3006
  });
3007
3007
  }
3008
3008
  }
3009
- const s = p15.spinner();
3010
- s.start(`Generating HTTP handler '${pc15.cyan(className)}'...`);
3009
+ const s = p3.spinner();
3010
+ s.start(`Generating HTTP handler '${pc14.cyan(className)}'...`);
3011
3011
  const options = {
3012
3012
  name: className,
3013
3013
  feature,
@@ -3025,7 +3025,7 @@ async function runHttpHandlerCommand(handlerNameArg, flags = {}) {
3025
3025
  const files = generateHttpHandler(options);
3026
3026
  s.stop("HTTP handler generated successfully!");
3027
3027
  printGeneratedFiles(files, options.dryRun);
3028
- p15.outro(pc15.green(`HTTP handler '${className}' created in feature '${feature}'!`));
3028
+ p3.outro(pc14.green(`HTTP handler '${className}' created in feature '${feature}'!`));
3029
3029
  }
3030
3030
  function generateInjectableCode(className, dependencies = [], methods = [], implementsInterface) {
3031
3031
  const formattedDeps = dependencies.map((dep) => ({
@@ -3035,7 +3035,7 @@ function generateInjectableCode(className, dependencies = [], methods = [], impl
3035
3035
  const formattedMethods = methods.map((m) => {
3036
3036
  const isAsync = m.async !== false;
3037
3037
  const retType = m.returnType ? isAsync ? `Promise<${m.returnType}>` : m.returnType : isAsync ? "Promise<void>" : "void";
3038
- const params = m.params && m.params.length > 0 ? m.params.map((p17) => `${p17.name}: ${p17.type}`).join(", ") : "";
3038
+ const params = m.params && m.params.length > 0 ? m.params.map((p16) => `${p16.name}: ${p16.type}`).join(", ") : "";
3039
3039
  return {
3040
3040
  name: m.name,
3041
3041
  isAsync,
@@ -3105,7 +3105,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3105
3105
  let name = classNameArg?.trim();
3106
3106
  if (!name) {
3107
3107
  name = handleCancel(
3108
- await p15.text({
3108
+ await p3.text({
3109
3109
  message: "Injectable class name:",
3110
3110
  placeholder: "e.g. PasswordHasher, TokenService, UserTransformer",
3111
3111
  validate: (v) => v && v.trim() ? void 0 : "Class name cannot be empty"
@@ -3118,7 +3118,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3118
3118
  let customPath;
3119
3119
  if (!flags.yes) {
3120
3120
  location = handleCancel(
3121
- await p15.select({
3121
+ await p3.select({
3122
3122
  message: "Select target architectural location:",
3123
3123
  options: [
3124
3124
  { value: "feature-service", label: "Feature Service (features/<feature>/services/)" },
@@ -3136,14 +3136,14 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3136
3136
  const featureOptions = existingFeatures.map((f) => ({ value: f, label: f }));
3137
3137
  featureOptions.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom feature name..." });
3138
3138
  const selected = handleCancel(
3139
- await p15.select({
3139
+ await p3.select({
3140
3140
  message: "Select target feature:",
3141
3141
  options: featureOptions
3142
3142
  })
3143
3143
  );
3144
3144
  if (selected === "__custom__") {
3145
3145
  feature = handleCancel(
3146
- await p15.text({
3146
+ await p3.text({
3147
3147
  message: "Enter feature name:",
3148
3148
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
3149
3149
  })
@@ -3153,7 +3153,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3153
3153
  }
3154
3154
  } else {
3155
3155
  feature = handleCancel(
3156
- await p15.text({
3156
+ await p3.text({
3157
3157
  message: "Enter target feature name:",
3158
3158
  validate: (v) => v && v.trim() ? void 0 : "Feature name cannot be empty"
3159
3159
  })
@@ -3163,7 +3163,7 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3163
3163
  feature = toCamelCase(feature);
3164
3164
  } else if (location === "custom") {
3165
3165
  customPath = handleCancel(
3166
- await p15.text({
3166
+ await p3.text({
3167
3167
  message: "Enter destination directory path:",
3168
3168
  placeholder: "e.g. src/services or lib/utils",
3169
3169
  validate: (v) => v && v.trim() ? void 0 : "Path cannot be empty"
@@ -3174,14 +3174,14 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3174
3174
  let generateInterface2 = false;
3175
3175
  if (!flags.yes) {
3176
3176
  generateInterface2 = handleCancel(
3177
- await p15.confirm({
3177
+ await p3.confirm({
3178
3178
  message: `Generate abstract class interface (I${className}) as runtime DI token?`,
3179
3179
  initialValue: false
3180
3180
  })
3181
3181
  );
3182
3182
  }
3183
- const s = p15.spinner();
3184
- s.start(`Generating injectable '${pc15.cyan(className)}'...`);
3183
+ const s = p3.spinner();
3184
+ s.start(`Generating injectable '${pc14.cyan(className)}'...`);
3185
3185
  const options = {
3186
3186
  name: className,
3187
3187
  feature,
@@ -3195,12 +3195,12 @@ async function runInjectableCommand(classNameArg, flags = {}) {
3195
3195
  const files = generateInjectable(options);
3196
3196
  s.stop("Injectable class generated successfully!");
3197
3197
  printGeneratedFiles(files, options.dryRun);
3198
- p15.outro(pc15.green(`Injectable '${className}' created successfully!`));
3198
+ p3.outro(pc14.green(`Injectable '${className}' created successfully!`));
3199
3199
  }
3200
3200
  async function runInteractiveMenu(flags = {}) {
3201
3201
  printBanner();
3202
3202
  const choice = handleCancel(
3203
- await p15.select({
3203
+ await p3.select({
3204
3204
  message: "What would you like to create in your architecture?",
3205
3205
  options: [
3206
3206
  {
@@ -3308,8 +3308,8 @@ async function handleCreate(type, name, flags = {}) {
3308
3308
  await runInjectableCommand(name, flags);
3309
3309
  break;
3310
3310
  default:
3311
- p15.log.error(
3312
- pc15.red(
3311
+ p3.log.error(
3312
+ pc14.red(
3313
3313
  `Unknown component type: "${type}". Allowed types: feature, shared, usecase, domain, infrastructure, interface, httpHandler, injectable.`
3314
3314
  )
3315
3315
  );
@@ -3341,7 +3341,7 @@ function findLocalRegistry(startDir = process.cwd()) {
3341
3341
  let current = path2.resolve(startDir);
3342
3342
  while (true) {
3343
3343
  const candidate = path2.join(current, "mason-registry");
3344
- if (fs12.existsSync(candidate) && fs12.existsSync(path2.join(candidate, "index.json"))) {
3344
+ if (fs9.existsSync(candidate) && fs9.existsSync(path2.join(candidate, "index.json"))) {
3345
3345
  return candidate;
3346
3346
  }
3347
3347
  const parent = path2.dirname(current);
@@ -3363,9 +3363,9 @@ function getRegistryBase(projectRoot, override) {
3363
3363
  path2.join(process.cwd(), "mason.config.json")
3364
3364
  ];
3365
3365
  for (const configPath of configLocations) {
3366
- if (fs12.existsSync(configPath)) {
3366
+ if (fs9.existsSync(configPath)) {
3367
3367
  try {
3368
- const config = JSON.parse(fs12.readFileSync(configPath, "utf-8"));
3368
+ const config = JSON.parse(fs9.readFileSync(configPath, "utf-8"));
3369
3369
  if (config.registry && typeof config.registry === "string") {
3370
3370
  return normalizeRegistryUrl(config.registry.trim(), path2.dirname(configPath));
3371
3371
  }
@@ -3378,9 +3378,9 @@ function getRegistryBase(projectRoot, override) {
3378
3378
  path2.join(process.cwd(), "package.json")
3379
3379
  ];
3380
3380
  for (const pkgPath of pkgLocations) {
3381
- if (fs12.existsSync(pkgPath)) {
3381
+ if (fs9.existsSync(pkgPath)) {
3382
3382
  try {
3383
- const pkg = JSON.parse(fs12.readFileSync(pkgPath, "utf-8"));
3383
+ const pkg = JSON.parse(fs9.readFileSync(pkgPath, "utf-8"));
3384
3384
  if (pkg.mason?.registry && typeof pkg.mason.registry === "string") {
3385
3385
  return normalizeRegistryUrl(pkg.mason.registry.trim(), path2.dirname(pkgPath));
3386
3386
  }
@@ -3424,10 +3424,10 @@ async function fetchRegistryFile(registryBase, relPath) {
3424
3424
  baseDir = fileURLToPath(baseDir);
3425
3425
  }
3426
3426
  const filePath = path2.resolve(baseDir, cleanRelPath);
3427
- if (!fs12.existsSync(filePath)) {
3427
+ if (!fs9.existsSync(filePath)) {
3428
3428
  throw new Error(`Registry file not found at ${filePath}`);
3429
3429
  }
3430
- return fs12.promises.readFile(filePath, "utf-8");
3430
+ return fs9.promises.readFile(filePath, "utf-8");
3431
3431
  }
3432
3432
  async function fetchRegistryIndex(registryBase) {
3433
3433
  const content = await fetchRegistryFile(registryBase, "index.json");
@@ -3489,26 +3489,26 @@ function findClosestMatch(target, candidates) {
3489
3489
  return null;
3490
3490
  }
3491
3491
  function detectPackageManager(projectRoot) {
3492
- if (fs12.existsSync(path2.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
3493
- if (fs12.existsSync(path2.join(projectRoot, "yarn.lock"))) return "yarn";
3494
- if (fs12.existsSync(path2.join(projectRoot, "bun.lockb")) || fs12.existsSync(path2.join(projectRoot, "bun.lock"))) return "bun";
3492
+ if (fs9.existsSync(path2.join(projectRoot, "pnpm-lock.yaml"))) return "pnpm";
3493
+ if (fs9.existsSync(path2.join(projectRoot, "yarn.lock"))) return "yarn";
3494
+ if (fs9.existsSync(path2.join(projectRoot, "bun.lockb")) || fs9.existsSync(path2.join(projectRoot, "bun.lock"))) return "bun";
3495
3495
  return "npm";
3496
3496
  }
3497
3497
  function getMissingNpmPackages(projectRoot, requiredPackages) {
3498
3498
  if (!requiredPackages || requiredPackages.length === 0) return [];
3499
3499
  const pkgJsonPath = path2.join(projectRoot, "package.json");
3500
- if (!fs12.existsSync(pkgJsonPath)) {
3500
+ if (!fs9.existsSync(pkgJsonPath)) {
3501
3501
  return requiredPackages;
3502
3502
  }
3503
3503
  try {
3504
- const pkg = JSON.parse(fs12.readFileSync(pkgJsonPath, "utf-8"));
3504
+ const pkg = JSON.parse(fs9.readFileSync(pkgJsonPath, "utf-8"));
3505
3505
  const installed = /* @__PURE__ */ new Set([
3506
3506
  ...Object.keys(pkg.dependencies || {}),
3507
3507
  ...Object.keys(pkg.devDependencies || {}),
3508
3508
  ...Object.keys(pkg.peerDependencies || {})
3509
3509
  ]);
3510
- return requiredPackages.filter((p17) => {
3511
- const nameOnly = p17.startsWith("@") ? `@${p17.slice(1).split("@")[0] || ""}` : p17.split("@")[0] || p17;
3510
+ return requiredPackages.filter((p16) => {
3511
+ const nameOnly = p16.startsWith("@") ? `@${p16.slice(1).split("@")[0] || ""}` : p16.split("@")[0] || p16;
3512
3512
  return !installed.has(nameOnly);
3513
3513
  });
3514
3514
  } catch {
@@ -3533,15 +3533,15 @@ function installNpmPackages(projectRoot, packages, pm) {
3533
3533
  installCmd = `npm install ${packages.join(" ")}`;
3534
3534
  break;
3535
3535
  }
3536
- p15.log.info(`Installing missing dependencies with ${manager}: ${pc15.cyan(packages.join(", "))}`);
3536
+ p3.log.info(`Installing missing dependencies with ${manager}: ${pc14.cyan(packages.join(", "))}`);
3537
3537
  execSync(installCmd, {
3538
3538
  cwd: projectRoot,
3539
3539
  stdio: "inherit"
3540
3540
  });
3541
3541
  }
3542
3542
  function getAllFiles(dir, baseDir = dir) {
3543
- if (!fs12.existsSync(dir)) return [];
3544
- const entries = fs12.readdirSync(dir, { withFileTypes: true });
3543
+ if (!fs9.existsSync(dir)) return [];
3544
+ const entries = fs9.readdirSync(dir, { withFileTypes: true });
3545
3545
  const files = [];
3546
3546
  for (const entry of entries) {
3547
3547
  const fullPath = path2.join(dir, entry.name);
@@ -3561,13 +3561,13 @@ function getAllFiles(dir, baseDir = dir) {
3561
3561
  return files.sort();
3562
3562
  }
3563
3563
  function computeDirectoryHash(dirPath, files) {
3564
- if (!fs12.existsSync(dirPath)) return "";
3564
+ if (!fs9.existsSync(dirPath)) return "";
3565
3565
  const hash = createHash("sha256");
3566
- const fileList = (files ?? getAllFiles(dirPath)).sort();
3566
+ const fileList = (getAllFiles(dirPath)).sort();
3567
3567
  for (const relativePath of fileList) {
3568
3568
  const absolutePath = path2.join(dirPath, relativePath);
3569
- if (!fs12.existsSync(absolutePath)) continue;
3570
- const content = fs12.readFileSync(absolutePath, "utf8");
3569
+ if (!fs9.existsSync(absolutePath)) continue;
3570
+ const content = fs9.readFileSync(absolutePath, "utf8");
3571
3571
  const normalizedContent = content.replace(/\r\n/g, "\n");
3572
3572
  hash.update(relativePath);
3573
3573
  hash.update(normalizedContent);
@@ -3577,8 +3577,8 @@ function computeDirectoryHash(dirPath, files) {
3577
3577
 
3578
3578
  // src/commands/import.ts
3579
3579
  var importPrompts = {
3580
- select: p15.select,
3581
- text: p15.text
3580
+ select: p3.select,
3581
+ text: p3.text
3582
3582
  };
3583
3583
  function rewriteImports(content, aliasMap) {
3584
3584
  if (aliasMap.size === 0) return content;
@@ -3599,9 +3599,9 @@ function getModuleBaseDir(projectRoot, modType) {
3599
3599
  function getExistingModuleDir(projectRoot, modType, modName) {
3600
3600
  const folder = modType === "shared" ? "shared" : "features";
3601
3601
  const inSrc = path2.join(projectRoot, "src", folder, modName);
3602
- if (fs12.existsSync(inSrc)) return inSrc;
3602
+ if (fs9.existsSync(inSrc)) return inSrc;
3603
3603
  const inRoot = path2.join(projectRoot, folder, modName);
3604
- if (fs12.existsSync(inRoot)) return inRoot;
3604
+ if (fs9.existsSync(inRoot)) return inRoot;
3605
3605
  return null;
3606
3606
  }
3607
3607
  function checkModuleExists(projectRoot, modType, modName) {
@@ -3619,13 +3619,13 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
3619
3619
  projectRoot,
3620
3620
  path2.join(baseDir, programmaticAlias)
3621
3621
  );
3622
- p15.log.step(`Importing '${depName}' into '${displayDest}'...`);
3622
+ p3.log.step(`Importing '${depName}' into '${displayDest}'...`);
3623
3623
  await importModuleRecursive(depType, depName, programmaticAlias);
3624
3624
  return;
3625
3625
  }
3626
3626
  const existingDir = getExistingModuleDir(projectRoot, depType, depName);
3627
3627
  if (!existingDir) {
3628
- p15.log.info(` \u21B3 Resolving required ${depType} dependency: ${pc15.cyan(depName)}`);
3628
+ p3.log.info(` \u21B3 Resolving required ${depType} dependency: ${pc14.cyan(depName)}`);
3629
3629
  await importModuleRecursive(depType, depName, depName);
3630
3630
  return;
3631
3631
  }
@@ -3642,25 +3642,25 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
3642
3642
  }
3643
3643
  const localHash = computeDirectoryHash(existingDir);
3644
3644
  if (remoteIntegrity && localHash === remoteIntegrity) {
3645
- p15.log.step(`\u2713 ${depType}/${depName} is up to date (reusing existing)`);
3645
+ p3.log.step(`\u2713 ${depType}/${depName} is up to date (reusing existing)`);
3646
3646
  importedModules.add(`${depType}:${depName}`);
3647
3647
  return;
3648
3648
  }
3649
3649
  if (flags.overwrite) {
3650
- p15.log.step(`Overwriting '${depType}/${depName}' with registry version (--overwrite)...`);
3650
+ p3.log.step(`Overwriting '${depType}/${depName}' with registry version (--overwrite)...`);
3651
3651
  const baseDir = getModuleBaseDir(projectRoot, depType);
3652
3652
  const targetDir = path2.join(baseDir, depName);
3653
3653
  if (!flags.dryRun) {
3654
3654
  if (existingDir !== targetDir) {
3655
- fs12.rmSync(existingDir, { recursive: true, force: true });
3655
+ fs9.rmSync(existingDir, { recursive: true, force: true });
3656
3656
  }
3657
- fs12.rmSync(targetDir, { recursive: true, force: true });
3657
+ fs9.rmSync(targetDir, { recursive: true, force: true });
3658
3658
  }
3659
3659
  await importModuleRecursive(depType, depName, depName, { overwrite: true });
3660
3660
  return;
3661
3661
  }
3662
3662
  if (flags.yes) {
3663
- p15.log.info(`Using existing '${depType}/${depName}'`);
3663
+ p3.log.info(`Using existing '${depType}/${depName}'`);
3664
3664
  importedModules.add(`${depType}:${depName}`);
3665
3665
  return;
3666
3666
  }
@@ -3684,7 +3684,7 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
3684
3684
  })
3685
3685
  );
3686
3686
  if (choice === "keep_existing" || choice === "use_existing") {
3687
- p15.log.step(`Skipping '${depType}/${depName}' (keeping existing)`);
3687
+ p3.log.step(`Skipping '${depType}/${depName}' (keeping existing)`);
3688
3688
  importedModules.add(`${depType}:${depName}`);
3689
3689
  return;
3690
3690
  }
@@ -3709,19 +3709,19 @@ async function resolveDependency(depType, depName, aliasMap, projectRoot, flags,
3709
3709
  aliasMap.set(`@/${folder}/${depName}/`, `@/${folder}/${newName}/`);
3710
3710
  const baseDir = getModuleBaseDir(projectRoot, depType);
3711
3711
  const displayDest = path2.relative(projectRoot, path2.join(baseDir, newName));
3712
- p15.log.step(`Importing '${depName}' into '${displayDest}'...`);
3712
+ p3.log.step(`Importing '${depName}' into '${displayDest}'...`);
3713
3713
  await importModuleRecursive(depType, depName, newName);
3714
3714
  return;
3715
3715
  }
3716
3716
  if (choice === "overwrite") {
3717
- p15.log.step(`Overwriting '${depType}/${depName}' with registry version...`);
3717
+ p3.log.step(`Overwriting '${depType}/${depName}' with registry version...`);
3718
3718
  const baseDir = getModuleBaseDir(projectRoot, depType);
3719
3719
  const targetDir = path2.join(baseDir, depName);
3720
3720
  if (!flags.dryRun) {
3721
3721
  if (existingDir !== targetDir) {
3722
- fs12.rmSync(existingDir, { recursive: true, force: true });
3722
+ fs9.rmSync(existingDir, { recursive: true, force: true });
3723
3723
  }
3724
- fs12.rmSync(targetDir, { recursive: true, force: true });
3724
+ fs9.rmSync(targetDir, { recursive: true, force: true });
3725
3725
  }
3726
3726
  await importModuleRecursive(depType, depName, depName, { overwrite: true });
3727
3727
  return;
@@ -3751,19 +3751,19 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3751
3751
  );
3752
3752
  }
3753
3753
  if (type !== "shared" && type !== "feature") {
3754
- p15.log.error(pc15.red(`Invalid module type: "${typeArg}". Must be "shared" or "feature".`));
3754
+ p3.log.error(pc14.red(`Invalid module type: "${typeArg}". Must be "shared" or "feature".`));
3755
3755
  process.exit(1);
3756
3756
  }
3757
3757
  const registryBase = getRegistryBase(projectRoot, flags.registry);
3758
- const s = p15.spinner();
3759
- s.start(`Connecting to registry at ${pc15.dim(registryBase)}...`);
3758
+ const s = p3.spinner();
3759
+ s.start(`Connecting to registry at ${pc14.dim(registryBase)}...`);
3760
3760
  let index;
3761
3761
  try {
3762
3762
  index = await fetchRegistryIndex(registryBase);
3763
3763
  s.stop("Registry index loaded.");
3764
3764
  } catch (err) {
3765
- s.stop(pc15.red("Failed to load registry index."));
3766
- p15.log.error(pc15.red(err.message || String(err)));
3765
+ s.stop(pc14.red("Failed to load registry index."));
3766
+ p3.log.error(pc14.red(err.message || String(err)));
3767
3767
  process.exit(1);
3768
3768
  }
3769
3769
  const availableList = type === "shared" ? index.shared : index.features;
@@ -3771,7 +3771,7 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3771
3771
  let name = nameArg?.trim();
3772
3772
  if (!name) {
3773
3773
  if (availableList.length === 0) {
3774
- p15.log.warn(`No ${type} modules available in the registry.`);
3774
+ p3.log.warn(`No ${type} modules available in the registry.`);
3775
3775
  return;
3776
3776
  }
3777
3777
  name = handleCancel(
@@ -3787,9 +3787,9 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3787
3787
  }
3788
3788
  if (!candidateNames.includes(name)) {
3789
3789
  const closest = findClosestMatch(name, candidateNames);
3790
- p15.log.error(pc15.red(`\u274C Module '${name}' not found in the ${type} registry.`));
3790
+ p3.log.error(pc14.red(`\u274C Module '${name}' not found in the ${type} registry.`));
3791
3791
  if (closest) {
3792
- p15.log.info(pc15.yellow(`Did you mean '${pc15.cyan(closest)}'?`));
3792
+ p3.log.info(pc14.yellow(`Did you mean '${pc14.cyan(closest)}'?`));
3793
3793
  }
3794
3794
  process.exit(1);
3795
3795
  }
@@ -3799,14 +3799,14 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3799
3799
  async function importModuleRecursive(modType, registryName, targetName = registryName, options) {
3800
3800
  const modKey = `${modType}:${targetName}`;
3801
3801
  if (importedModules.has(modKey)) return;
3802
- p15.log.step(
3803
- `Importing ${modType}: ${pc15.cyan(targetName)}${targetName !== registryName ? pc15.dim(` (from ${registryName})`) : ""}...`
3802
+ p3.log.step(
3803
+ `Importing ${modType}: ${pc14.cyan(targetName)}${targetName !== registryName ? pc14.dim(` (from ${registryName})`) : ""}...`
3804
3804
  );
3805
3805
  let manifest;
3806
3806
  try {
3807
3807
  manifest = await fetchModuleManifest(registryBase, modType, registryName);
3808
3808
  } catch (err) {
3809
- p15.log.error(pc15.red(`Failed to fetch manifest for ${modType} '${registryName}': ${err.message}`));
3809
+ p3.log.error(pc14.red(`Failed to fetch manifest for ${modType} '${registryName}': ${err.message}`));
3810
3810
  process.exit(1);
3811
3811
  }
3812
3812
  const aliasMap = /* @__PURE__ */ new Map();
@@ -3852,21 +3852,21 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3852
3852
  if (file === "registry.json") continue;
3853
3853
  const remoteFilePath = `${folder}/${registryName}/${file}`;
3854
3854
  const localFilePath = path2.join(targetDir, file);
3855
- if (fs12.existsSync(localFilePath) && !isOverwrite) {
3856
- p15.log.warn(
3857
- ` \u21B3 Skipping existing file: ${pc15.dim(path2.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
3855
+ if (fs9.existsSync(localFilePath) && !isOverwrite) {
3856
+ p3.log.warn(
3857
+ ` \u21B3 Skipping existing file: ${pc14.dim(path2.relative(projectRoot, localFilePath))} (use --overwrite to replace)`
3858
3858
  );
3859
3859
  continue;
3860
3860
  }
3861
3861
  let content = await fetchRegistryFile(registryBase, remoteFilePath);
3862
3862
  content = rewriteImports(content, aliasMap);
3863
3863
  if (!flags.dryRun) {
3864
- fs12.mkdirSync(path2.dirname(localFilePath), { recursive: true });
3865
- fs12.writeFileSync(localFilePath, content, "utf-8");
3864
+ fs9.mkdirSync(path2.dirname(localFilePath), { recursive: true });
3865
+ fs9.writeFileSync(localFilePath, content, "utf-8");
3866
3866
  }
3867
3867
  const displayPath = path2.relative(projectRoot, localFilePath);
3868
3868
  totalWrittenFiles.push(displayPath);
3869
- p15.log.message(` ${pc15.green("+")} ${displayPath}`);
3869
+ p3.log.message(` ${pc14.green("+")} ${displayPath}`);
3870
3870
  }
3871
3871
  importedModules.add(modKey);
3872
3872
  }
@@ -3874,564 +3874,35 @@ async function handleImport(typeArg, nameArg, flags = {}) {
3874
3874
  const missingNpm = getMissingNpmPackages(projectRoot, Array.from(requiredNpmPackages));
3875
3875
  if (missingNpm.length > 0) {
3876
3876
  if (flags.skipInstall || flags.dryRun) {
3877
- p15.log.info(`Required npm dependencies to install: ${pc15.cyan(missingNpm.join(", "))}`);
3877
+ p3.log.info(`Required npm dependencies to install: ${pc14.cyan(missingNpm.join(", "))}`);
3878
3878
  } else {
3879
3879
  try {
3880
3880
  installNpmPackages(projectRoot, missingNpm);
3881
3881
  } catch (err) {
3882
- p15.log.warn(`Could not automatically install packages (${err.message}). Please run: npm install ${missingNpm.join(" ")}`);
3882
+ p3.log.warn(`Could not automatically install packages (${err.message}). Please run: npm install ${missingNpm.join(" ")}`);
3883
3883
  }
3884
3884
  }
3885
3885
  }
3886
3886
  if (flags.dryRun) {
3887
- p15.log.info(pc15.yellow("Dry run complete: No files were written to disk."));
3887
+ p3.log.info(pc14.yellow("Dry run complete: No files were written to disk."));
3888
3888
  } else {
3889
3889
  const baseDir = getModuleBaseDir(projectRoot, type);
3890
3890
  const displayTarget = path2.relative(projectRoot, path2.join(baseDir, name));
3891
- p15.log.success(
3892
- pc15.green(
3891
+ p3.log.success(
3892
+ pc14.green(
3893
3893
  `Successfully imported ${type} '${name}' (${totalWrittenFiles.length} file${totalWrittenFiles.length === 1 ? "" : "s"} placed in ${displayTarget})`
3894
3894
  )
3895
3895
  );
3896
3896
  }
3897
3897
  }
3898
- function loadMasterIndex(projectRoot) {
3899
- const indexPath = path2.join(projectRoot, "index.json");
3900
- if (!fs12.existsSync(indexPath)) {
3901
- const initialIndex = { shared: [], features: [] };
3902
- fs12.writeFileSync(indexPath, JSON.stringify(initialIndex, null, 2) + "\n", "utf-8");
3903
- return initialIndex;
3904
- }
3905
- return JSON.parse(fs12.readFileSync(indexPath, "utf-8"));
3906
- }
3907
- function saveMasterIndex(projectRoot, index) {
3908
- const indexPath = path2.join(projectRoot, "index.json");
3909
- index.shared.sort((a, b) => a.name.localeCompare(b.name));
3910
- index.features.sort((a, b) => a.name.localeCompare(b.name));
3911
- fs12.writeFileSync(indexPath, JSON.stringify(index, null, 2) + "\n", "utf-8");
3912
- }
3913
- function discoverDiskModules(projectRoot) {
3914
- const results = [];
3915
- const sharedDir = resolveSharedDir(projectRoot);
3916
- if (fs12.existsSync(sharedDir)) {
3917
- const entries = fs12.readdirSync(sharedDir, { withFileTypes: true });
3918
- for (const entry of entries) {
3919
- if (entry.isDirectory() && !entry.name.startsWith(".")) {
3920
- results.push({ name: entry.name, type: "shared", dir: path2.join(sharedDir, entry.name) });
3921
- }
3922
- }
3923
- }
3924
- const featuresDir = resolveFeaturesDir(projectRoot);
3925
- if (fs12.existsSync(featuresDir)) {
3926
- const entries = fs12.readdirSync(featuresDir, { withFileTypes: true });
3927
- for (const entry of entries) {
3928
- if (entry.isDirectory() && !entry.name.startsWith(".")) {
3929
- results.push({ name: entry.name, type: "feature", dir: path2.join(featuresDir, entry.name) });
3930
- }
3931
- }
3932
- }
3933
- return results;
3934
- }
3935
- function checkGitStatusForDir(projectRoot, dirPath) {
3936
- try {
3937
- const relPath = path2.relative(projectRoot, dirPath);
3938
- const output = execSync(`git status --porcelain -- "${relPath}"`, {
3939
- cwd: projectRoot,
3940
- stdio: ["ignore", "pipe", "ignore"],
3941
- encoding: "utf-8"
3942
- }).trim();
3943
- if (!output) {
3944
- return { hasChanges: false, filesCount: 0 };
3945
- }
3946
- const lines = output.split("\n").filter((l) => l.trim().length > 0);
3947
- return { hasChanges: true, filesCount: lines.length };
3948
- } catch {
3949
- return { hasChanges: false, filesCount: 0 };
3950
- }
3951
- }
3952
- function getRegistryDiff(projectRoot) {
3953
- const index = loadMasterIndex(projectRoot);
3954
- const diskModules = discoverDiskModules(projectRoot);
3955
- const diskMap = /* @__PURE__ */ new Map();
3956
- for (const mod of diskModules) {
3957
- diskMap.set(`${mod.type}:${mod.name}`, mod);
3958
- }
3959
- const allKeys = /* @__PURE__ */ new Set();
3960
- for (const item of index.shared) {
3961
- allKeys.add(`shared:${item.name}`);
3962
- }
3963
- for (const item of index.features) {
3964
- allKeys.add(`feature:${item.name}`);
3965
- }
3966
- for (const mod of diskModules) {
3967
- allKeys.add(`${mod.type}:${mod.name}`);
3968
- }
3969
- const statuses = [];
3970
- for (const key of allKeys) {
3971
- const [typeStr, name] = key.split(":");
3972
- const type = typeStr;
3973
- const registeredEntry = (type === "shared" ? index.shared : index.features).find(
3974
- (e) => e.name === name
3975
- );
3976
- const isRegistered = Boolean(registeredEntry);
3977
- const diskInfo = diskMap.get(key);
3978
- const existsOnDisk = Boolean(diskInfo && fs12.existsSync(diskInfo.dir));
3979
- let hasUncommittedGitChanges = false;
3980
- let uncommittedFilesCount = 0;
3981
- let hasIntegrityDrift = false;
3982
- let localIntegrity;
3983
- if (existsOnDisk && diskInfo) {
3984
- const git = checkGitStatusForDir(projectRoot, diskInfo.dir);
3985
- hasUncommittedGitChanges = git.hasChanges;
3986
- uncommittedFilesCount = git.filesCount;
3987
- localIntegrity = computeDirectoryHash(diskInfo.dir);
3988
- if (isRegistered && registeredEntry?.integrity) {
3989
- hasIntegrityDrift = localIntegrity !== registeredEntry.integrity;
3990
- }
3991
- }
3992
- statuses.push({
3993
- name,
3994
- type,
3995
- isRegistered,
3996
- existsOnDisk,
3997
- hasUncommittedGitChanges,
3998
- uncommittedFilesCount,
3999
- hasIntegrityDrift,
4000
- localIntegrity,
4001
- registeredIntegrity: registeredEntry?.integrity
4002
- });
4003
- }
4004
- return statuses.sort((a, b) => a.type.localeCompare(b.type) || a.name.localeCompare(b.name));
4005
- }
4006
- async function registerModule(typeArg, nameArg, flags = {}) {
4007
- const projectRoot = findProjectRoot();
4008
- const index = loadMasterIndex(projectRoot);
4009
- let type = typeArg?.trim();
4010
- if (!type) {
4011
- type = handleCancel(
4012
- await p15.select({
4013
- message: "Module type to register:",
4014
- options: [
4015
- { value: "feature", label: "Feature" },
4016
- { value: "shared", label: "Shared Module" }
4017
- ]
4018
- })
4019
- );
4020
- }
4021
- const diskModules = discoverDiskModules(projectRoot).filter((m) => m.type === type);
4022
- const registeredNames = new Set((type === "shared" ? index.shared : index.features).map((m) => m.name));
4023
- const unregistered = diskModules.filter((m) => !registeredNames.has(m.name));
4024
- let name = nameArg?.trim();
4025
- if (!name) {
4026
- if (unregistered.length > 0) {
4027
- const opts = unregistered.map((m) => ({ value: m.name, label: m.name, hint: "unregistered on disk" }));
4028
- opts.push({ value: "__custom__", label: "\u270F\uFE0F Enter custom name...", hint: "" });
4029
- const choice = handleCancel(
4030
- await p15.select({
4031
- message: `Select a ${type} to register:`,
4032
- options: opts
4033
- })
4034
- );
4035
- if (choice === "__custom__") {
4036
- name = handleCancel(
4037
- await p15.text({
4038
- message: `Enter ${type} name:`,
4039
- validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
4040
- })
4041
- ).trim();
4042
- } else {
4043
- name = choice;
4044
- }
4045
- } else {
4046
- name = handleCancel(
4047
- await p15.text({
4048
- message: `Enter ${type} name to register:`,
4049
- validate: (v) => v && v.trim() ? void 0 : "Name cannot be empty"
4050
- })
4051
- ).trim();
4052
- }
4053
- }
4054
- const folder = type === "shared" ? resolveSharedDir(projectRoot) : resolveFeaturesDir(projectRoot);
4055
- const modDir = path2.join(folder, name);
4056
- if (!fs12.existsSync(modDir)) {
4057
- p15.log.error(pc15.red(`Module directory does not exist: ${path2.relative(projectRoot, modDir)}`));
4058
- process.exit(1);
4059
- }
4060
- const files = getAllFiles(modDir);
4061
- const integrity = computeDirectoryHash(modDir, files);
4062
- const manifestPath = path2.join(modDir, "registry.json");
4063
- let manifest;
4064
- if (fs12.existsSync(manifestPath)) {
4065
- manifest = JSON.parse(fs12.readFileSync(manifestPath, "utf-8"));
4066
- } else {
4067
- manifest = {
4068
- name,
4069
- type,
4070
- description: `${name} ${type} module`,
4071
- version: "1.0.0",
4072
- dependencies: {
4073
- npm: [],
4074
- shared: [],
4075
- features: []
4076
- },
4077
- files: []
4078
- };
4079
- }
4080
- manifest.name = name;
4081
- manifest.type = type;
4082
- manifest.files = files;
4083
- manifest.integrity = integrity;
4084
- fs12.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
4085
- const targetList = type === "shared" ? index.shared : index.features;
4086
- const existingIdx = targetList.findIndex((item) => item.name === name);
4087
- if (existingIdx >= 0) {
4088
- targetList[existingIdx] = {
4089
- name,
4090
- description: manifest.description,
4091
- version: manifest.version,
4092
- integrity
4093
- };
4094
- } else {
4095
- targetList.push({
4096
- name,
4097
- description: manifest.description,
4098
- version: manifest.version,
4099
- integrity
4100
- });
4101
- }
4102
- saveMasterIndex(projectRoot, index);
4103
- p15.log.success(
4104
- pc15.green(
4105
- `\u2713 Module '${type}/${name}' registered in index.json (${files.length} files, ${integrity.slice(0, 18)}...)`
4106
- )
4107
- );
4108
- }
4109
- async function commitModule(typeArg, nameArg, flags = {}) {
4110
- const projectRoot = findProjectRoot();
4111
- let type = typeArg?.trim();
4112
- if (!type) {
4113
- type = handleCancel(
4114
- await p15.select({
4115
- message: "Module type to commit:",
4116
- options: [
4117
- { value: "feature", label: "Feature" },
4118
- { value: "shared", label: "Shared Module" }
4119
- ]
4120
- })
4121
- );
4122
- }
4123
- let name = nameArg?.trim();
4124
- if (!name) {
4125
- const diskModules = discoverDiskModules(projectRoot).filter((m) => m.type === type);
4126
- const opts = diskModules.map((m) => {
4127
- const git = checkGitStatusForDir(projectRoot, m.dir);
4128
- return {
4129
- value: m.name,
4130
- label: m.name,
4131
- hint: git.hasChanges ? `${git.filesCount} uncommitted files` : "clean working tree"
4132
- };
4133
- });
4134
- name = handleCancel(
4135
- await p15.select({
4136
- message: `Select ${type} to commit:`,
4137
- options: opts
4138
- })
4139
- );
4140
- }
4141
- const folder = type === "shared" ? resolveSharedDir(projectRoot) : resolveFeaturesDir(projectRoot);
4142
- const modDir = path2.join(folder, name);
4143
- if (!fs12.existsSync(modDir)) {
4144
- p15.log.error(pc15.red(`Module directory does not exist: ${path2.relative(projectRoot, modDir)}`));
4145
- process.exit(1);
4146
- }
4147
- const relModDir = path2.relative(projectRoot, modDir);
4148
- const gitStatus = checkGitStatusForDir(projectRoot, modDir);
4149
- if (!gitStatus.hasChanges) {
4150
- p15.log.warn(pc15.yellow(`No uncommitted git changes found in '${type}/${name}'.`));
4151
- return;
4152
- }
4153
- let message = flags.message?.trim();
4154
- if (!message) {
4155
- message = handleCancel(
4156
- await p15.text({
4157
- message: `Commit message for ${type}/${name}:`,
4158
- placeholder: `e.g. feat(${name}): update use cases and dependencies`,
4159
- validate: (v) => v && v.trim() ? void 0 : "Commit message cannot be empty"
4160
- })
4161
- ).trim();
4162
- }
4163
- const s = p15.spinner();
4164
- s.start(`Committing '${type}/${name}' to git repository...`);
4165
- try {
4166
- execSync(`git add "${relModDir}"`, { cwd: projectRoot, stdio: ["ignore", "pipe", "pipe"] });
4167
- execSync(`git commit -m "${message.replace(/"/g, '\\"')}" -- "${relModDir}"`, {
4168
- cwd: projectRoot,
4169
- stdio: ["ignore", "pipe", "pipe"]
4170
- });
4171
- s.stop(`Changes for '${type}/${name}' committed to git.`);
4172
- p15.log.success(pc15.green(`\u2713 Committed '${type}/${name}': "${message}"`));
4173
- } catch (err) {
4174
- s.stop(pc15.red("Git commit failed."));
4175
- p15.log.error(pc15.red(err.message || String(err)));
4176
- process.exit(1);
4177
- }
4178
- }
4179
- async function registerModuleChanges(typeArg, nameArg, flags = {}) {
4180
- const projectRoot = findProjectRoot();
4181
- const index = loadMasterIndex(projectRoot);
4182
- let type = typeArg?.trim();
4183
- if (!type) {
4184
- type = handleCancel(
4185
- await p15.select({
4186
- message: "Module type to update:",
4187
- options: [
4188
- { value: "feature", label: "Feature" },
4189
- { value: "shared", label: "Shared Module" }
4190
- ]
4191
- })
4192
- );
4193
- }
4194
- let name = nameArg?.trim();
4195
- if (!name) {
4196
- const diskModules = discoverDiskModules(projectRoot).filter((m) => m.type === type);
4197
- const diffs = getRegistryDiff(projectRoot).filter((d) => d.type === type && d.isRegistered);
4198
- const opts = diskModules.map((m) => {
4199
- const d = diffs.find((item) => item.name === m.name);
4200
- return {
4201
- value: m.name,
4202
- label: m.name,
4203
- hint: d?.hasIntegrityDrift ? "drift detected (needs register)" : "up to date"
4204
- };
4205
- });
4206
- name = handleCancel(
4207
- await p15.select({
4208
- message: `Select ${type} to register changes:`,
4209
- options: opts
4210
- })
4211
- );
4212
- }
4213
- const folder = type === "shared" ? resolveSharedDir(projectRoot) : resolveFeaturesDir(projectRoot);
4214
- const modDir = path2.join(folder, name);
4215
- if (!fs12.existsSync(modDir)) {
4216
- p15.log.error(pc15.red(`Module directory does not exist: ${path2.relative(projectRoot, modDir)}`));
4217
- process.exit(1);
4218
- }
4219
- const files = getAllFiles(modDir);
4220
- const integrity = computeDirectoryHash(modDir, files);
4221
- const manifestPath = path2.join(modDir, "registry.json");
4222
- let manifest;
4223
- if (fs12.existsSync(manifestPath)) {
4224
- manifest = JSON.parse(fs12.readFileSync(manifestPath, "utf-8"));
4225
- } else {
4226
- manifest = {
4227
- name,
4228
- type,
4229
- description: `${name} ${type} module`,
4230
- version: "1.0.0",
4231
- dependencies: { npm: [], shared: [], features: [] },
4232
- files: []
4233
- };
4234
- }
4235
- manifest.files = files;
4236
- manifest.integrity = integrity;
4237
- if (flags.version) {
4238
- manifest.version = flags.version;
4239
- }
4240
- fs12.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf-8");
4241
- const targetList = type === "shared" ? index.shared : index.features;
4242
- const existingIdx = targetList.findIndex((item) => item.name === name);
4243
- if (existingIdx >= 0) {
4244
- targetList[existingIdx] = {
4245
- name,
4246
- description: manifest.description,
4247
- version: manifest.version,
4248
- integrity
4249
- };
4250
- } else {
4251
- targetList.push({
4252
- name,
4253
- description: manifest.description,
4254
- version: manifest.version,
4255
- integrity
4256
- });
4257
- }
4258
- saveMasterIndex(projectRoot, index);
4259
- p15.log.success(
4260
- pc15.green(`\u2713 Registered changes for '${type}/${name}' (new integrity: ${integrity.slice(0, 18)}...)`)
4261
- );
4262
- }
4263
- async function unregisterModule(typeArg, nameArg, flags = {}) {
4264
- const projectRoot = findProjectRoot();
4265
- const index = loadMasterIndex(projectRoot);
4266
- let type = typeArg?.trim();
4267
- if (!type) {
4268
- type = handleCancel(
4269
- await p15.select({
4270
- message: "Module type to unregister:",
4271
- options: [
4272
- { value: "feature", label: "Feature" },
4273
- { value: "shared", label: "Shared Module" }
4274
- ]
4275
- })
4276
- );
4277
- }
4278
- const registeredList = type === "shared" ? index.shared : index.features;
4279
- if (registeredList.length === 0) {
4280
- p15.log.warn(`No registered ${type} modules found in index.json.`);
4281
- return;
4282
- }
4283
- let name = nameArg?.trim();
4284
- if (!name) {
4285
- name = handleCancel(
4286
- await p15.select({
4287
- message: `Select ${type} to unregister from index.json:`,
4288
- options: registeredList.map((item) => ({
4289
- value: item.name,
4290
- label: item.name,
4291
- hint: item.description
4292
- }))
4293
- })
4294
- );
4295
- }
4296
- if (type === "shared") {
4297
- index.shared = index.shared.filter((item) => item.name !== name);
4298
- } else {
4299
- index.features = index.features.filter((item) => item.name !== name);
4300
- }
4301
- saveMasterIndex(projectRoot, index);
4302
- p15.log.success(
4303
- pc15.green(
4304
- `\u2713 Unregistered module '${type}/${name}' from index.json (source code retained on disk in ${type === "shared" ? "shared" : "features"}/${name})`
4305
- )
4306
- );
4307
- }
4308
- function diffRegistry(flags = {}) {
4309
- const projectRoot = findProjectRoot();
4310
- const diffs = getRegistryDiff(projectRoot);
4311
- p15.log.step(pc15.bold("\u{1F4CB} Mason Registry Diff & Status Summary"));
4312
- const unregistered = diffs.filter((d) => d.existsOnDisk && !d.isRegistered);
4313
- const uncommitted = diffs.filter((d) => d.existsOnDisk && d.hasUncommittedGitChanges);
4314
- const committedDrift = diffs.filter(
4315
- (d) => d.existsOnDisk && d.isRegistered && !d.hasUncommittedGitChanges && d.hasIntegrityDrift
4316
- );
4317
- const upToDate = diffs.filter(
4318
- (d) => d.existsOnDisk && d.isRegistered && !d.hasUncommittedGitChanges && !d.hasIntegrityDrift
4319
- );
4320
- const missing = diffs.filter((d) => !d.existsOnDisk && d.isRegistered);
4321
- if (unregistered.length > 0) {
4322
- p15.log.message(pc15.yellow(`
4323
- \u{1F4E6} Unregistered Modules (${unregistered.length}):`));
4324
- for (const mod of unregistered) {
4325
- p15.log.message(` ${pc15.red("\u25CF")} ${pc15.bold(`${mod.type}/${mod.name}`)} ${pc15.dim("(not registered in index.json)")}`);
4326
- }
4327
- }
4328
- if (uncommitted.length > 0) {
4329
- p15.log.message(pc15.yellow(`
4330
- \u{1F4BE} Uncommitted Changes in Git (${uncommitted.length}):`));
4331
- for (const mod of uncommitted) {
4332
- p15.log.message(
4333
- ` ${pc15.yellow("\u25B2")} ${pc15.bold(`${mod.type}/${mod.name}`)} ${pc15.dim(`(${mod.uncommittedFilesCount} modified/untracked files)`)}`
4334
- );
4335
- }
4336
- }
4337
- if (committedDrift.length > 0) {
4338
- p15.log.message(pc15.cyan(`
4339
- \u{1F680} Committed But Unregistered Changes (${committedDrift.length}):`));
4340
- for (const mod of committedDrift) {
4341
- p15.log.message(
4342
- ` ${pc15.cyan("\u25C6")} ${pc15.bold(`${mod.type}/${mod.name}`)} ${pc15.dim(
4343
- `local: ${mod.localIntegrity?.slice(0, 16)}... != registered: ${mod.registeredIntegrity?.slice(0, 16)}...`
4344
- )}`
4345
- );
4346
- }
4347
- }
4348
- if (missing.length > 0) {
4349
- p15.log.message(pc15.red(`
4350
- \u26A0\uFE0F Missing on Disk (${missing.length}):`));
4351
- for (const mod of missing) {
4352
- p15.log.message(` ${pc15.red("\u2715")} ${pc15.bold(`${mod.type}/${mod.name}`)} ${pc15.dim("(in index.json, but folder missing)")}`);
4353
- }
4354
- }
4355
- if (upToDate.length > 0) {
4356
- p15.log.message(pc15.green(`
4357
- \u2713 Up to Date & Registered (${upToDate.length}):`));
4358
- for (const mod of upToDate) {
4359
- p15.log.message(` ${pc15.green("\u2714")} ${mod.type}/${mod.name} ${pc15.dim(`(${mod.registeredIntegrity?.slice(0, 18)}...)`)}`);
4360
- }
4361
- }
4362
- p15.log.message("");
4363
- }
4364
- async function handleRegistry(actionArg, typeArg, nameArg, flags = {}) {
4365
- let action = actionArg?.trim().toLowerCase();
4366
- if (!action) {
4367
- action = handleCancel(
4368
- await p15.select({
4369
- message: "\u{1F3DB}\uFE0F Mason Registry: What would you like to do?",
4370
- options: [
4371
- {
4372
- value: "diff",
4373
- label: "Inspect Diff & Status",
4374
- hint: "Summary of unregistered, uncommitted, and drifted modules"
4375
- },
4376
- {
4377
- value: "register",
4378
- label: "Register Module",
4379
- hint: "Add an existing module to index.json with integrity checksum"
4380
- },
4381
- {
4382
- value: "commit",
4383
- label: "Commit Changes",
4384
- hint: "Commit a module's working changes to git in the background"
4385
- },
4386
- {
4387
- value: "register-changes",
4388
- label: "Register Changes",
4389
- hint: "Update index.json & registry.json with latest checksums"
4390
- },
4391
- {
4392
- value: "unregister",
4393
- label: "Unregister Module",
4394
- hint: "Remove module from index.json (source code stays on disk)"
4395
- }
4396
- ]
4397
- })
4398
- );
4399
- }
4400
- switch (action) {
4401
- case "diff":
4402
- case "status":
4403
- diffRegistry(flags);
4404
- break;
4405
- case "register":
4406
- await registerModule(typeArg, nameArg, flags);
4407
- break;
4408
- case "commit":
4409
- await commitModule(typeArg, nameArg, flags);
4410
- break;
4411
- case "register-changes":
4412
- case "update":
4413
- await registerModuleChanges(typeArg, nameArg, flags);
4414
- break;
4415
- case "unregister":
4416
- await unregisterModule(typeArg, nameArg, flags);
4417
- break;
4418
- default:
4419
- p15.log.error(
4420
- pc15.red(
4421
- `Unknown registry action: "${action}". Valid actions: diff, register, commit, register-changes, unregister.`
4422
- )
4423
- );
4424
- process.exit(1);
4425
- }
4426
- }
4427
3898
 
4428
3899
  // src/cli.ts
4429
3900
  function createCli() {
4430
3901
  const cli = cac("mason");
4431
3902
  cli.command("[...args]", "Interactive scaffolding and import wizard").option("-d, --dry-run", "Preview changes without writing to disk").option("-o, --overwrite", "Overwrite existing files").option("-y, --yes", "Accept defaults and skip interactive prompts").option("--registry", "Run in registry mode").action(async (args, flags) => {
4432
3903
  if (args && args.length > 0) {
4433
- p15.log.error(
4434
- pc15.red(
3904
+ p3.log.error(
3905
+ pc14.red(
4435
3906
  `Unknown command: "${args.join(" ")}". Use --help to list available commands.`
4436
3907
  )
4437
3908
  );
@@ -4442,14 +3913,9 @@ function createCli() {
4442
3913
  const mode = getEffectiveMode(projectRoot, flags);
4443
3914
  if (mode === "registry") {
4444
3915
  const choice2 = handleCancel(
4445
- await p15.select({
4446
- message: "\u{1F3DB}\uFE0F Mason Registry Maintainer: What would you like to do?",
3916
+ await p3.select({
3917
+ message: "\u{1F3DB}\uFE0F Mason (Registry Mode): What would you like to scaffold?",
4447
3918
  options: [
4448
- {
4449
- value: "diff",
4450
- label: "Inspect Diff & Status",
4451
- hint: "Overview of unregistered, uncommitted, or drifted modules"
4452
- },
4453
3919
  {
4454
3920
  value: "create_feature",
4455
3921
  label: "Initialize New Feature",
@@ -4465,26 +3931,6 @@ function createCli() {
4465
3931
  label: "Create New Use Case",
4466
3932
  hint: "Add a new use case to an existing feature"
4467
3933
  },
4468
- {
4469
- value: "register",
4470
- label: "Register Module",
4471
- hint: "Add a module to index.json with integrity checksum"
4472
- },
4473
- {
4474
- value: "commit",
4475
- label: "Commit Module Changes",
4476
- hint: "Commit working changes in a module to git"
4477
- },
4478
- {
4479
- value: "register_changes",
4480
- label: "Register Changes",
4481
- hint: "Recompute checksums and update index.json"
4482
- },
4483
- {
4484
- value: "unregister",
4485
- label: "Unregister Module",
4486
- hint: "Remove from index.json but keep source on disk"
4487
- },
4488
3934
  {
4489
3935
  value: "import",
4490
3936
  label: "Import from Remote Registry",
@@ -4494,9 +3940,6 @@ function createCli() {
4494
3940
  })
4495
3941
  );
4496
3942
  switch (choice2) {
4497
- case "diff":
4498
- await handleRegistry("diff", void 0, void 0, flags);
4499
- break;
4500
3943
  case "create_feature":
4501
3944
  await handleCreate("feature", void 0, flags);
4502
3945
  break;
@@ -4506,18 +3949,6 @@ function createCli() {
4506
3949
  case "create_usecase":
4507
3950
  await handleCreate("usecase", void 0, flags);
4508
3951
  break;
4509
- case "register":
4510
- await handleRegistry("register", void 0, void 0, flags);
4511
- break;
4512
- case "commit":
4513
- await handleRegistry("commit", void 0, void 0, flags);
4514
- break;
4515
- case "register_changes":
4516
- await handleRegistry("register-changes", void 0, void 0, flags);
4517
- break;
4518
- case "unregister":
4519
- await handleRegistry("unregister", void 0, void 0, flags);
4520
- break;
4521
3952
  case "import":
4522
3953
  await handleImport(void 0, void 0, flags);
4523
3954
  break;
@@ -4525,31 +3956,24 @@ function createCli() {
4525
3956
  return;
4526
3957
  }
4527
3958
  const choice = handleCancel(
4528
- await p15.select({
3959
+ await p3.select({
4529
3960
  message: "\u{1F9F1} Mason: What would you like to do?",
4530
3961
  options: [
4531
3962
  {
4532
3963
  value: "create",
4533
- label: "Create local component",
3964
+ label: "Create component",
4534
3965
  hint: "Scaffold a new feature, shared module, use case, domain entity, etc."
4535
3966
  },
4536
3967
  {
4537
3968
  value: "import",
4538
3969
  label: "Import from registry",
4539
3970
  hint: "Download and link pre-built shared modules or features from the registry"
4540
- },
4541
- {
4542
- value: "registry",
4543
- label: "Registry management",
4544
- hint: "Inspect diff, register modules, or commit module changes"
4545
3971
  }
4546
3972
  ]
4547
3973
  })
4548
3974
  );
4549
3975
  if (choice === "create") {
4550
3976
  await handleCreate(void 0, void 0, flags);
4551
- } else if (choice === "registry") {
4552
- await handleRegistry(void 0, void 0, void 0, flags);
4553
3977
  } else {
4554
3978
  await handleImport(void 0, void 0, flags);
4555
3979
  }
@@ -4577,25 +4001,6 @@ function createCli() {
4577
4001
  handleCliError(err);
4578
4002
  }
4579
4003
  });
4580
- cli.command(
4581
- "registry [action] [type] [name]",
4582
- "Registry & version management (diff, register, commit, register-changes, unregister)"
4583
- ).option("-m, --message <message>", "Commit message for 'commit' command").option("-y, --yes", "Accept defaults and skip interactive prompts").example("mason registry diff").example("mason registry register feature authn").example("mason registry commit shared hasher -m 'Add bcrypt engine'").example("mason registry register-changes shared hasher").example("mason registry unregister feature oldFeature").action(
4584
- async (action, type, name, flags = {}) => {
4585
- try {
4586
- await handleRegistry(action, type, name, flags);
4587
- } catch (err) {
4588
- handleCliError(err);
4589
- }
4590
- }
4591
- );
4592
- cli.command("diff", "Inspect registry status and diff (alias for 'mason registry diff')").allowUnknownOptions().action(async (flags = {}) => {
4593
- try {
4594
- await handleRegistry("diff", void 0, void 0, flags);
4595
- } catch (err) {
4596
- handleCliError(err);
4597
- }
4598
- });
4599
4004
  const createSubtypes = [
4600
4005
  "feature",
4601
4006
  "shared",
@@ -4619,7 +4024,7 @@ function createCli() {
4619
4024
  });
4620
4025
  }
4621
4026
  cli.help();
4622
- cli.version("1.0.13");
4027
+ cli.version("1.0.14");
4623
4028
  return cli;
4624
4029
  }
4625
4030
  function handleCliError(err) {
@@ -4627,7 +4032,7 @@ function handleCliError(err) {
4627
4032
  process.exit(0);
4628
4033
  }
4629
4034
  const message = err instanceof Error ? err.message : String(err);
4630
- p15.log.error(pc15.red(`Error: ${message}`));
4035
+ p3.log.error(pc14.red(`Error: ${message}`));
4631
4036
  process.exit(1);
4632
4037
  }
4633
4038
  async function runCli(argv = process.argv) {