@objectstack/cli 3.0.4 → 3.0.6

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @objectstack/cli@3.0.4 build /home/runner/work/spec/spec/packages/cli
2
+ > @objectstack/cli@3.0.6 build /home/runner/work/spec/spec/packages/cli
3
3
  > tsup
4
4
 
5
5
  CLI Building entry: src/bin.ts
@@ -15,14 +15,14 @@
15
15
  ESM Build start
16
16
  CLI Cleaning output folder
17
17
  ESM Build start
18
- ESM dist/index.js 94.66 KB
19
- ESM dist/config-UN34WBHT.js 151.00 B
20
- ESM dist/chunk-CSHQEILI.js 7.29 KB
21
- ESM ⚡️ Build success in 238ms
22
- ESM dist/bin.js 131.47 KB
23
- ESM dist/config-A7BN6UIT.js 171.00 B
24
- ESM dist/chunk-Q74JNWKD.js 7.31 KB
25
- ESM ⚡️ Build success in 257ms
18
+ ESM dist/index.js 95.12 KB
19
+ ESM dist/config-FOXDQ5F7.js 151.00 B
20
+ ESM dist/chunk-T2YN4AB7.js 7.49 KB
21
+ ESM ⚡️ Build success in 344ms
22
+ ESM dist/bin.js 132.06 KB
23
+ ESM dist/config-GBR54FKL.js 171.00 B
24
+ ESM dist/chunk-XNACYTC5.js 7.51 KB
25
+ ESM ⚡️ Build success in 323ms
26
26
  DTS Build start
27
- DTS ⚡️ Build success in 14403ms
27
+ DTS ⚡️ Build success in 14199ms
28
28
  DTS dist/index.d.ts 3.42 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # @objectstack/cli
2
2
 
3
+ ## 3.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5df254c]
8
+ - @objectstack/spec@3.0.6
9
+ - @objectstack/core@3.0.6
10
+ - @objectstack/objectql@3.0.6
11
+ - @objectstack/driver-memory@3.0.6
12
+ - @objectstack/plugin-hono-server@3.0.6
13
+ - @objectstack/rest@3.0.6
14
+ - @objectstack/runtime@3.0.6
15
+
16
+ ## 3.0.5
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [23a4a68]
21
+ - @objectstack/spec@3.0.5
22
+ - @objectstack/core@3.0.5
23
+ - @objectstack/objectql@3.0.5
24
+ - @objectstack/driver-memory@3.0.5
25
+ - @objectstack/plugin-hono-server@3.0.5
26
+ - @objectstack/rest@3.0.5
27
+ - @objectstack/runtime@3.0.5
28
+
3
29
  ## 3.0.4
4
30
 
5
31
  ### Patch Changes
package/dist/bin.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  printSuccess,
16
16
  printWarning,
17
17
  resolveConfigPath
18
- } from "./chunk-Q74JNWKD.js";
18
+ } from "./chunk-XNACYTC5.js";
19
19
 
20
20
  // src/bin.ts
21
21
  import { createRequire as createRequire2 } from "module";
@@ -27,7 +27,7 @@ import { Command } from "commander";
27
27
  import path from "path";
28
28
  import fs from "fs";
29
29
  import chalk from "chalk";
30
- import { ObjectStackDefinitionSchema } from "@objectstack/spec";
30
+ import { ObjectStackDefinitionSchema, normalizeStackInput } from "@objectstack/spec";
31
31
  var compileCommand = new Command("compile").description("Compile ObjectStack configuration to JSON artifact").argument("[config]", "Source configuration file").option("-o, --output <path>", "Output JSON file", "dist/objectstack.json").option("--json", "Output compile result as JSON (for CI)").action(async (configPath, options) => {
32
32
  const timer = createTimer();
33
33
  if (!options.json) {
@@ -41,7 +41,8 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
41
41
  printKV("Load time", `${duration}ms`);
42
42
  }
43
43
  if (!options.json) printStep("Validating protocol compliance...");
44
- const result = ObjectStackDefinitionSchema.safeParse(config);
44
+ const normalized = normalizeStackInput(config);
45
+ const result = ObjectStackDefinitionSchema.safeParse(normalized);
45
46
  if (!result.success) {
46
47
  if (options.json) {
47
48
  console.log(JSON.stringify({ success: false, errors: result.error.issues }));
@@ -141,6 +142,7 @@ import chalk3 from "chalk";
141
142
  import { execSync as execSync2 } from "child_process";
142
143
  import fs3 from "fs";
143
144
  import path3 from "path";
145
+ import { normalizeStackInput as normalizeStackInput2 } from "@objectstack/spec";
144
146
  function detectCircularDependencies(objects) {
145
147
  const issues = [];
146
148
  const graph = /* @__PURE__ */ new Map();
@@ -516,7 +518,8 @@ var doctorCommand = new Command3("doctor").description("Check development enviro
516
518
  if (configExists()) {
517
519
  printStep("Loading configuration for analysis...");
518
520
  try {
519
- const { config } = await loadConfig();
521
+ const { config: rawConfig } = await loadConfig();
522
+ const config = normalizeStackInput2(rawConfig);
520
523
  if (Array.isArray(config.objects) && config.objects.length > 0) {
521
524
  printStep("Checking for circular dependencies...");
522
525
  const cycles = detectCircularDependencies(config.objects);
@@ -1276,7 +1279,7 @@ var testCommand = new Command7("test").description("Run Quality Protocol test sc
1276
1279
  // src/commands/validate.ts
1277
1280
  import { Command as Command8 } from "commander";
1278
1281
  import chalk7 from "chalk";
1279
- import { ObjectStackDefinitionSchema as ObjectStackDefinitionSchema2 } from "@objectstack/spec";
1282
+ import { ObjectStackDefinitionSchema as ObjectStackDefinitionSchema2, normalizeStackInput as normalizeStackInput3 } from "@objectstack/spec";
1280
1283
  var validateCommand = new Command8("validate").description("Validate ObjectStack configuration against the protocol schema").argument("[config]", "Configuration file path").option("--strict", "Treat warnings as errors").option("--json", "Output results as JSON").action(async (configPath, options) => {
1281
1284
  const timer = createTimer();
1282
1285
  if (!options.json) {
@@ -1290,7 +1293,8 @@ var validateCommand = new Command8("validate").description("Validate ObjectStack
1290
1293
  printKV("Load time", `${duration}ms`);
1291
1294
  }
1292
1295
  if (!options.json) printStep("Validating against ObjectStack Protocol...");
1293
- const result = ObjectStackDefinitionSchema2.safeParse(config);
1296
+ const normalized = normalizeStackInput3(config);
1297
+ const result = ObjectStackDefinitionSchema2.safeParse(normalized);
1294
1298
  if (!result.success) {
1295
1299
  if (options.json) {
1296
1300
  console.log(JSON.stringify({
@@ -1643,13 +1647,15 @@ function printWarning2(msg) {
1643
1647
  // src/commands/info.ts
1644
1648
  import { Command as Command10 } from "commander";
1645
1649
  import chalk9 from "chalk";
1650
+ import { normalizeStackInput as normalizeStackInput4 } from "@objectstack/spec";
1646
1651
  var infoCommand = new Command10("info").description("Display metadata summary of an ObjectStack configuration").argument("[config]", "Configuration file path").option("--json", "Output as JSON").action(async (configPath, options) => {
1647
1652
  const timer = createTimer();
1648
1653
  if (!options.json) {
1649
1654
  printHeader("Info");
1650
1655
  }
1651
1656
  try {
1652
- const { config, absolutePath, duration } = await loadConfig(configPath);
1657
+ const { config: rawConfig, absolutePath, duration } = await loadConfig(configPath);
1658
+ const config = normalizeStackInput4(rawConfig);
1653
1659
  const stats = collectMetadataStats(config);
1654
1660
  if (options.json) {
1655
1661
  console.log(JSON.stringify({
@@ -2058,7 +2064,7 @@ var generateMetadataCommand = new Command11("metadata").alias("m").description("
2058
2064
  var generateTypesCommand = new Command11("types").description("Generate TypeScript type definitions from ObjectStack configuration").argument("[config]", "Configuration file path").option("-o, --output <file>", "Output file path", "src/types/objectstack.d.ts").option("--dry-run", "Show what would be generated without writing files").action(async (configPath, options) => {
2059
2065
  printHeader("Generate Types");
2060
2066
  try {
2061
- const { loadConfig: loadConfig2 } = await import("./config-A7BN6UIT.js");
2067
+ const { loadConfig: loadConfig2 } = await import("./config-GBR54FKL.js");
2062
2068
  printInfo("Loading configuration...");
2063
2069
  const { config, absolutePath } = await loadConfig2(configPath);
2064
2070
  console.log(` ${chalk10.dim("Config:")} ${chalk10.white(absolutePath)}`);
@@ -2167,7 +2173,7 @@ function generateClientFromConfig(config) {
2167
2173
  var generateClientCommand = new Command11("client").description("Generate a type-safe client SDK from ObjectStack configuration").argument("[config]", "Configuration file path").option("-o, --output <file>", "Output file path", "src/client/objectstack-client.ts").option("--dry-run", "Show output without writing").action(async (configPath, options) => {
2168
2174
  printHeader("Generate Client SDK");
2169
2175
  try {
2170
- const { loadConfig: loadConfig2 } = await import("./config-A7BN6UIT.js");
2176
+ const { loadConfig: loadConfig2 } = await import("./config-GBR54FKL.js");
2171
2177
  const timer = createTimer();
2172
2178
  printInfo("Loading configuration...");
2173
2179
  const { config, absolutePath } = await loadConfig2(configPath);
@@ -2380,7 +2386,7 @@ function generateMigrationTs(config) {
2380
2386
  var generateMigrationCommand = new Command11("migration").description("Generate database migration from ObjectStack schema").argument("[config]", "Configuration file path").option("-o, --output <file>", "Output file path").option("--format <format>", "Output format: sql or typescript", "typescript").option("--dry-run", "Show output without writing").action(async (configPath, options) => {
2381
2387
  printHeader("Generate Migration");
2382
2388
  try {
2383
- const { loadConfig: loadConfig2 } = await import("./config-A7BN6UIT.js");
2389
+ const { loadConfig: loadConfig2 } = await import("./config-GBR54FKL.js");
2384
2390
  const timer = createTimer();
2385
2391
  printInfo("Loading configuration...");
2386
2392
  const { config, absolutePath } = await loadConfig2(configPath);
@@ -2927,6 +2933,7 @@ var diffCommand = new Command13("diff").description("Compare two ObjectStack con
2927
2933
  // src/commands/lint.ts
2928
2934
  import { Command as Command14 } from "commander";
2929
2935
  import chalk13 from "chalk";
2936
+ import { normalizeStackInput as normalizeStackInput5 } from "@objectstack/spec";
2930
2937
  var SNAKE_CASE_RE = /^[a-z][a-z0-9_]*$/;
2931
2938
  function checkSnakeCase(value, path12, label) {
2932
2939
  if (!SNAKE_CASE_RE.test(value)) {
@@ -3062,7 +3069,8 @@ var lintCommand = new Command14("lint").description("Check ObjectStack configura
3062
3069
  if (!options.json) {
3063
3070
  printInfo(`Config: ${chalk13.white(absolutePath)}`);
3064
3071
  }
3065
- const issues = lintConfig(config);
3072
+ const normalized = normalizeStackInput5(config);
3073
+ const issues = lintConfig(normalized);
3066
3074
  if (options.json) {
3067
3075
  const errors2 = issues.filter((i) => i.severity === "error");
3068
3076
  const warnings2 = issues.filter((i) => i.severity === "warning");
@@ -72,13 +72,16 @@ function formatZodErrors(error) {
72
72
  console.log(chalk.dim(` ${issues.length} validation error(s) total`));
73
73
  }
74
74
  function collectMetadataStats(config) {
75
- const count = (arr) => Array.isArray(arr) ? arr.length : 0;
75
+ const count = (val) => {
76
+ if (Array.isArray(val)) return val.length;
77
+ if (val && typeof val === "object") return Object.keys(val).length;
78
+ return 0;
79
+ };
76
80
  let fields = 0;
77
- if (Array.isArray(config.objects)) {
78
- for (const obj of config.objects) {
79
- if (obj.fields && typeof obj.fields === "object") {
80
- fields += Object.keys(obj.fields).length;
81
- }
81
+ const objects = Array.isArray(config.objects) ? config.objects : config.objects && typeof config.objects === "object" ? Object.values(config.objects) : [];
82
+ for (const obj of objects) {
83
+ if (obj.fields && typeof obj.fields === "object") {
84
+ fields += Object.keys(obj.fields).length;
82
85
  }
83
86
  }
84
87
  return {
@@ -74,13 +74,16 @@ function formatZodErrors(error) {
74
74
  console.log(chalk.dim(` ${issues.length} validation error(s) total`));
75
75
  }
76
76
  function collectMetadataStats(config) {
77
- const count = (arr) => Array.isArray(arr) ? arr.length : 0;
77
+ const count = (val) => {
78
+ if (Array.isArray(val)) return val.length;
79
+ if (val && typeof val === "object") return Object.keys(val).length;
80
+ return 0;
81
+ };
78
82
  let fields = 0;
79
- if (Array.isArray(config.objects)) {
80
- for (const obj of config.objects) {
81
- if (obj.fields && typeof obj.fields === "object") {
82
- fields += Object.keys(obj.fields).length;
83
- }
83
+ const objects = Array.isArray(config.objects) ? config.objects : config.objects && typeof config.objects === "object" ? Object.values(config.objects) : [];
84
+ for (const obj of objects) {
85
+ if (obj.fields && typeof obj.fields === "object") {
86
+ fields += Object.keys(obj.fields).length;
84
87
  }
85
88
  }
86
89
  return {
@@ -2,7 +2,7 @@ import {
2
2
  configExists,
3
3
  loadConfig,
4
4
  resolveConfigPath
5
- } from "./chunk-CSHQEILI.js";
5
+ } from "./chunk-T2YN4AB7.js";
6
6
  export {
7
7
  configExists,
8
8
  loadConfig,
@@ -3,7 +3,7 @@ import {
3
3
  configExists,
4
4
  loadConfig,
5
5
  resolveConfigPath
6
- } from "./chunk-Q74JNWKD.js";
6
+ } from "./chunk-XNACYTC5.js";
7
7
  export {
8
8
  configExists,
9
9
  loadConfig,
package/dist/index.js CHANGED
@@ -14,14 +14,14 @@ import {
14
14
  printSuccess,
15
15
  printWarning,
16
16
  resolveConfigPath
17
- } from "./chunk-CSHQEILI.js";
17
+ } from "./chunk-T2YN4AB7.js";
18
18
 
19
19
  // src/commands/compile.ts
20
20
  import { Command } from "commander";
21
21
  import path from "path";
22
22
  import fs from "fs";
23
23
  import chalk from "chalk";
24
- import { ObjectStackDefinitionSchema } from "@objectstack/spec";
24
+ import { ObjectStackDefinitionSchema, normalizeStackInput } from "@objectstack/spec";
25
25
  var compileCommand = new Command("compile").description("Compile ObjectStack configuration to JSON artifact").argument("[config]", "Source configuration file").option("-o, --output <path>", "Output JSON file", "dist/objectstack.json").option("--json", "Output compile result as JSON (for CI)").action(async (configPath, options) => {
26
26
  const timer = createTimer();
27
27
  if (!options.json) {
@@ -35,7 +35,8 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
35
35
  printKV("Load time", `${duration}ms`);
36
36
  }
37
37
  if (!options.json) printStep("Validating protocol compliance...");
38
- const result = ObjectStackDefinitionSchema.safeParse(config);
38
+ const normalized = normalizeStackInput(config);
39
+ const result = ObjectStackDefinitionSchema.safeParse(normalized);
39
40
  if (!result.success) {
40
41
  if (options.json) {
41
42
  console.log(JSON.stringify({ success: false, errors: result.error.issues }));
@@ -88,7 +89,7 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
88
89
  // src/commands/validate.ts
89
90
  import { Command as Command2 } from "commander";
90
91
  import chalk2 from "chalk";
91
- import { ObjectStackDefinitionSchema as ObjectStackDefinitionSchema2 } from "@objectstack/spec";
92
+ import { ObjectStackDefinitionSchema as ObjectStackDefinitionSchema2, normalizeStackInput as normalizeStackInput2 } from "@objectstack/spec";
92
93
  var validateCommand = new Command2("validate").description("Validate ObjectStack configuration against the protocol schema").argument("[config]", "Configuration file path").option("--strict", "Treat warnings as errors").option("--json", "Output results as JSON").action(async (configPath, options) => {
93
94
  const timer = createTimer();
94
95
  if (!options.json) {
@@ -102,7 +103,8 @@ var validateCommand = new Command2("validate").description("Validate ObjectStack
102
103
  printKV("Load time", `${duration}ms`);
103
104
  }
104
105
  if (!options.json) printStep("Validating against ObjectStack Protocol...");
105
- const result = ObjectStackDefinitionSchema2.safeParse(config);
106
+ const normalized = normalizeStackInput2(config);
107
+ const result = ObjectStackDefinitionSchema2.safeParse(normalized);
106
108
  if (!result.success) {
107
109
  if (options.json) {
108
110
  console.log(JSON.stringify({
@@ -181,13 +183,15 @@ var validateCommand = new Command2("validate").description("Validate ObjectStack
181
183
  // src/commands/info.ts
182
184
  import { Command as Command3 } from "commander";
183
185
  import chalk3 from "chalk";
186
+ import { normalizeStackInput as normalizeStackInput3 } from "@objectstack/spec";
184
187
  var infoCommand = new Command3("info").description("Display metadata summary of an ObjectStack configuration").argument("[config]", "Configuration file path").option("--json", "Output as JSON").action(async (configPath, options) => {
185
188
  const timer = createTimer();
186
189
  if (!options.json) {
187
190
  printHeader("Info");
188
191
  }
189
192
  try {
190
- const { config, absolutePath, duration } = await loadConfig(configPath);
193
+ const { config: rawConfig, absolutePath, duration } = await loadConfig(configPath);
194
+ const config = normalizeStackInput3(rawConfig);
191
195
  const stats = collectMetadataStats(config);
192
196
  if (options.json) {
193
197
  console.log(JSON.stringify({
@@ -870,7 +874,7 @@ var generateMetadataCommand = new Command5("metadata").alias("m").description("G
870
874
  var generateTypesCommand = new Command5("types").description("Generate TypeScript type definitions from ObjectStack configuration").argument("[config]", "Configuration file path").option("-o, --output <file>", "Output file path", "src/types/objectstack.d.ts").option("--dry-run", "Show what would be generated without writing files").action(async (configPath, options) => {
871
875
  printHeader("Generate Types");
872
876
  try {
873
- const { loadConfig: loadConfig2 } = await import("./config-UN34WBHT.js");
877
+ const { loadConfig: loadConfig2 } = await import("./config-FOXDQ5F7.js");
874
878
  printInfo("Loading configuration...");
875
879
  const { config, absolutePath } = await loadConfig2(configPath);
876
880
  console.log(` ${chalk5.dim("Config:")} ${chalk5.white(absolutePath)}`);
@@ -979,7 +983,7 @@ function generateClientFromConfig(config) {
979
983
  var generateClientCommand = new Command5("client").description("Generate a type-safe client SDK from ObjectStack configuration").argument("[config]", "Configuration file path").option("-o, --output <file>", "Output file path", "src/client/objectstack-client.ts").option("--dry-run", "Show output without writing").action(async (configPath, options) => {
980
984
  printHeader("Generate Client SDK");
981
985
  try {
982
- const { loadConfig: loadConfig2 } = await import("./config-UN34WBHT.js");
986
+ const { loadConfig: loadConfig2 } = await import("./config-FOXDQ5F7.js");
983
987
  const timer = createTimer();
984
988
  printInfo("Loading configuration...");
985
989
  const { config, absolutePath } = await loadConfig2(configPath);
@@ -1192,7 +1196,7 @@ function generateMigrationTs(config) {
1192
1196
  var generateMigrationCommand = new Command5("migration").description("Generate database migration from ObjectStack schema").argument("[config]", "Configuration file path").option("-o, --output <file>", "Output file path").option("--format <format>", "Output format: sql or typescript", "typescript").option("--dry-run", "Show output without writing").action(async (configPath, options) => {
1193
1197
  printHeader("Generate Migration");
1194
1198
  try {
1195
- const { loadConfig: loadConfig2 } = await import("./config-UN34WBHT.js");
1199
+ const { loadConfig: loadConfig2 } = await import("./config-FOXDQ5F7.js");
1196
1200
  const timer = createTimer();
1197
1201
  printInfo("Loading configuration...");
1198
1202
  const { config, absolutePath } = await loadConfig2(configPath);
@@ -2249,6 +2253,7 @@ import chalk11 from "chalk";
2249
2253
  import { execSync as execSync2 } from "child_process";
2250
2254
  import fs10 from "fs";
2251
2255
  import path10 from "path";
2256
+ import { normalizeStackInput as normalizeStackInput4 } from "@objectstack/spec";
2252
2257
  function detectCircularDependencies(objects) {
2253
2258
  const issues = [];
2254
2259
  const graph = /* @__PURE__ */ new Map();
@@ -2624,7 +2629,8 @@ var doctorCommand = new Command11("doctor").description("Check development envir
2624
2629
  if (configExists()) {
2625
2630
  printStep("Loading configuration for analysis...");
2626
2631
  try {
2627
- const { config } = await loadConfig();
2632
+ const { config: rawConfig } = await loadConfig();
2633
+ const config = normalizeStackInput4(rawConfig);
2628
2634
  if (Array.isArray(config.objects) && config.objects.length > 0) {
2629
2635
  printStep("Checking for circular dependencies...");
2630
2636
  const cycles = detectCircularDependencies(config.objects);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectstack/cli",
3
- "version": "3.0.4",
3
+ "version": "3.0.6",
4
4
  "description": "Command Line Interface for ObjectStack Protocol",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -22,16 +22,16 @@
22
22
  "commander": "^14.0.3",
23
23
  "tsx": "^4.7.1",
24
24
  "zod": "^4.3.6",
25
- "@objectstack/core": "3.0.4",
26
- "@objectstack/driver-memory": "^3.0.4",
27
- "@objectstack/objectql": "^3.0.4",
28
- "@objectstack/plugin-hono-server": "3.0.4",
29
- "@objectstack/rest": "3.0.4",
30
- "@objectstack/runtime": "^3.0.4",
31
- "@objectstack/spec": "3.0.4"
25
+ "@objectstack/core": "3.0.6",
26
+ "@objectstack/driver-memory": "^3.0.6",
27
+ "@objectstack/objectql": "^3.0.6",
28
+ "@objectstack/plugin-hono-server": "3.0.6",
29
+ "@objectstack/rest": "3.0.6",
30
+ "@objectstack/runtime": "^3.0.6",
31
+ "@objectstack/spec": "3.0.6"
32
32
  },
33
33
  "peerDependencies": {
34
- "@objectstack/core": "3.0.4"
34
+ "@objectstack/core": "3.0.6"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/node": "^25.2.2",
@@ -5,7 +5,7 @@ import path from 'path';
5
5
  import fs from 'fs';
6
6
  import chalk from 'chalk';
7
7
  import { ZodError } from 'zod';
8
- import { ObjectStackDefinitionSchema } from '@objectstack/spec';
8
+ import { ObjectStackDefinitionSchema, normalizeStackInput } from '@objectstack/spec';
9
9
  import { loadConfig } from '../utils/config.js';
10
10
  import {
11
11
  printHeader,
@@ -41,9 +41,10 @@ export const compileCommand = new Command('compile')
41
41
  printKV('Load time', `${duration}ms`);
42
42
  }
43
43
 
44
- // 2. Validate against Protocol
44
+ // 2. Normalize map-formatted stack definition and validate against Protocol
45
45
  if (!options.json) printStep('Validating protocol compliance...');
46
- const result = ObjectStackDefinitionSchema.safeParse(config);
46
+ const normalized = normalizeStackInput(config as Record<string, unknown>);
47
+ const result = ObjectStackDefinitionSchema.safeParse(normalized);
47
48
 
48
49
  if (!result.success) {
49
50
  if (options.json) {
@@ -5,6 +5,7 @@ import chalk from 'chalk';
5
5
  import { execSync } from 'child_process';
6
6
  import fs from 'fs';
7
7
  import path from 'path';
8
+ import { normalizeStackInput } from '@objectstack/spec';
8
9
  import { printHeader, printSuccess, printWarning, printError, printStep, printInfo } from '../utils/format.js';
9
10
  import { loadConfig, configExists } from '../utils/config.js';
10
11
 
@@ -476,7 +477,8 @@ export const doctorCommand = new Command('doctor')
476
477
  if (configExists()) {
477
478
  printStep('Loading configuration for analysis...');
478
479
  try {
479
- const { config } = await loadConfig();
480
+ const { config: rawConfig } = await loadConfig();
481
+ const config: any = normalizeStackInput(rawConfig as Record<string, unknown>);
480
482
 
481
483
  // Circular dependency detection
482
484
  if (Array.isArray(config.objects) && config.objects.length > 0) {
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
+ import { normalizeStackInput } from '@objectstack/spec';
5
6
  import { loadConfig } from '../utils/config.js';
6
7
  import {
7
8
  printHeader,
@@ -26,7 +27,8 @@ export const infoCommand = new Command('info')
26
27
  }
27
28
 
28
29
  try {
29
- const { config, absolutePath, duration } = await loadConfig(configPath);
30
+ const { config: rawConfig, absolutePath, duration } = await loadConfig(configPath);
31
+ const config: any = normalizeStackInput(rawConfig as Record<string, unknown>);
30
32
  const stats = collectMetadataStats(config);
31
33
 
32
34
  if (options.json) {
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
+ import { normalizeStackInput } from '@objectstack/spec';
5
6
  import { loadConfig } from '../utils/config.js';
6
7
  import {
7
8
  printHeader,
@@ -207,7 +208,8 @@ export const lintCommand = new Command('lint')
207
208
  printInfo(`Config: ${chalk.white(absolutePath)}`);
208
209
  }
209
210
 
210
- const issues = lintConfig(config);
211
+ const normalized = normalizeStackInput(config as Record<string, unknown>);
212
+ const issues = lintConfig(normalized);
211
213
 
212
214
  // ── JSON output ──
213
215
  if (options.json) {
@@ -3,7 +3,7 @@
3
3
  import { Command } from 'commander';
4
4
  import chalk from 'chalk';
5
5
  import { ZodError } from 'zod';
6
- import { ObjectStackDefinitionSchema } from '@objectstack/spec';
6
+ import { ObjectStackDefinitionSchema, normalizeStackInput } from '@objectstack/spec';
7
7
  import { loadConfig } from '../utils/config.js';
8
8
  import {
9
9
  printHeader,
@@ -39,9 +39,10 @@ export const validateCommand = new Command('validate')
39
39
  printKV('Load time', `${duration}ms`);
40
40
  }
41
41
 
42
- // 2. Validate against schema
42
+ // 2. Normalize map-formatted stack definition and validate against schema
43
43
  if (!options.json) printStep('Validating against ObjectStack Protocol...');
44
- const result = ObjectStackDefinitionSchema.safeParse(config);
44
+ const normalized = normalizeStackInput(config as Record<string, unknown>);
45
+ const result = ObjectStackDefinitionSchema.safeParse(normalized);
45
46
 
46
47
  if (!result.success) {
47
48
  if (options.json) {
@@ -134,15 +134,19 @@ export interface MetadataStats {
134
134
  }
135
135
 
136
136
  export function collectMetadataStats(config: any): MetadataStats {
137
- const count = (arr: any) => (Array.isArray(arr) ? arr.length : 0);
137
+ const count = (val: any) => {
138
+ if (Array.isArray(val)) return val.length;
139
+ if (val && typeof val === 'object') return Object.keys(val).length;
140
+ return 0;
141
+ };
138
142
 
139
143
  // Count total fields across all objects
140
144
  let fields = 0;
141
- if (Array.isArray(config.objects)) {
142
- for (const obj of config.objects) {
143
- if (obj.fields && typeof obj.fields === 'object') {
144
- fields += Object.keys(obj.fields).length;
145
- }
145
+ const objects = Array.isArray(config.objects) ? config.objects :
146
+ (config.objects && typeof config.objects === 'object' ? Object.values(config.objects) : []);
147
+ for (const obj of objects as any[]) {
148
+ if (obj.fields && typeof obj.fields === 'object') {
149
+ fields += Object.keys(obj.fields).length;
146
150
  }
147
151
  }
148
152