@objectstack/cli 3.0.5 → 3.0.7
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/.turbo/turbo-build.log +2 -26
- package/CHANGELOG.md +27 -0
- package/README.md +98 -54
- package/bin/run-dev.js +5 -0
- package/bin/run.js +5 -0
- package/dist/bin.d.ts +11 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +12 -3759
- package/dist/bin.js.map +1 -0
- package/dist/commands/codemod/v2-to-v3.d.ts +10 -0
- package/dist/commands/codemod/v2-to-v3.d.ts.map +1 -0
- package/dist/commands/codemod/v2-to-v3.js +145 -0
- package/dist/commands/codemod/v2-to-v3.js.map +1 -0
- package/dist/commands/compile.d.ts +13 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +91 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/create.d.ts +91 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +259 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +67 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/diff.d.ts +16 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +239 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +532 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/explain.d.ts +12 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +368 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/generate.d.ts +17 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +833 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/info.d.ts +12 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +100 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +22 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +295 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +13 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +255 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/plugin/add.d.ts +22 -0
- package/dist/commands/plugin/add.d.ts.map +1 -0
- package/dist/commands/plugin/add.js +93 -0
- package/dist/commands/plugin/add.js.map +1 -0
- package/dist/commands/plugin/info.d.ts +10 -0
- package/dist/commands/plugin/info.d.ts.map +1 -0
- package/dist/commands/plugin/info.js +65 -0
- package/dist/commands/plugin/info.js.map +1 -0
- package/dist/commands/plugin/list.d.ts +13 -0
- package/dist/commands/plugin/list.d.ts.map +1 -0
- package/dist/commands/plugin/list.js +78 -0
- package/dist/commands/plugin/list.js.map +1 -0
- package/dist/commands/plugin/remove.d.ts +20 -0
- package/dist/commands/plugin/remove.d.ts.map +1 -0
- package/dist/commands/plugin/remove.js +79 -0
- package/dist/commands/plugin/remove.js.map +1 -0
- package/dist/commands/serve.d.ts +15 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +286 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/studio.d.ts +19 -0
- package/dist/commands/studio.d.ts.map +1 -0
- package/dist/commands/studio.js +43 -0
- package/dist/commands/studio.js.map +1 -0
- package/dist/commands/test.d.ts +13 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +120 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/validate.d.ts +13 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +115 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +15 -114
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -2799
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +21 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +66 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/format.d.ts +52 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +202 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/plugin-helpers.d.ts +14 -0
- package/dist/utils/plugin-helpers.d.ts.map +1 -0
- package/dist/utils/plugin-helpers.js +40 -0
- package/dist/utils/plugin-helpers.js.map +1 -0
- package/dist/utils/studio.d.ts +58 -0
- package/dist/utils/studio.d.ts.map +1 -0
- package/dist/utils/studio.js +288 -0
- package/dist/utils/studio.js.map +1 -0
- package/package.json +33 -15
- package/src/bin.ts +11 -104
- package/src/commands/{codemod.ts → codemod/v2-to-v3.ts} +21 -28
- package/src/commands/compile.ts +35 -25
- package/src/commands/create.ts +29 -19
- package/src/commands/dev.ts +21 -10
- package/src/commands/diff.ts +28 -19
- package/src/commands/doctor.ts +20 -11
- package/src/commands/explain.ts +20 -10
- package/src/commands/generate.ts +81 -90
- package/src/commands/info.ts +22 -11
- package/src/commands/init.ts +32 -20
- package/src/commands/lint.ts +27 -15
- package/src/commands/plugin/add.ts +112 -0
- package/src/commands/plugin/info.ts +79 -0
- package/src/commands/plugin/list.ts +93 -0
- package/src/commands/plugin/remove.ts +97 -0
- package/src/commands/serve.ts +30 -20
- package/src/commands/studio.ts +21 -11
- package/src/commands/test.ts +21 -10
- package/src/commands/validate.ts +36 -25
- package/src/index.ts +20 -12
- package/src/utils/format.ts +10 -6
- package/src/utils/plugin-helpers.ts +37 -0
- package/src/utils/studio.ts +0 -1
- package/test/commands.test.ts +76 -37
- package/test/plugin-commands.test.ts +42 -160
- package/test/plugin.test.ts +19 -23
- package/tsconfig.build.json +18 -0
- package/bin/objectstack.js +0 -2
- package/dist/chunk-CSHQEILI.js +0 -246
- package/dist/chunk-Q74JNWKD.js +0 -248
- package/dist/config-A7BN6UIT.js +0 -11
- package/dist/config-UN34WBHT.js +0 -10
- package/src/commands/plugin.ts +0 -372
- package/src/utils/plugin-commands.ts +0 -163
package/src/commands/compile.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
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,
|
|
@@ -19,46 +19,55 @@ import {
|
|
|
19
19
|
printMetadataStats,
|
|
20
20
|
} from '../utils/format.js';
|
|
21
21
|
|
|
22
|
-
export
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
export default class Compile extends Command {
|
|
23
|
+
static override description = 'Compile ObjectStack configuration to JSON artifact';
|
|
24
|
+
|
|
25
|
+
static override args = {
|
|
26
|
+
config: Args.string({ description: 'Source configuration file', required: false }),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
static override flags = {
|
|
30
|
+
output: Flags.string({ char: 'o', description: 'Output JSON file', default: 'dist/objectstack.json' }),
|
|
31
|
+
json: Flags.boolean({ description: 'Output compile result as JSON (for CI)' }),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
async run(): Promise<void> {
|
|
35
|
+
const { args, flags } = await this.parse(Compile);
|
|
28
36
|
const timer = createTimer();
|
|
29
37
|
|
|
30
|
-
if (!
|
|
38
|
+
if (!flags.json) {
|
|
31
39
|
printHeader('Compile');
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
try {
|
|
35
43
|
// 1. Load Configuration
|
|
36
|
-
if (!
|
|
37
|
-
const { config, absolutePath, duration } = await loadConfig(
|
|
44
|
+
if (!flags.json) printStep('Loading configuration...');
|
|
45
|
+
const { config, absolutePath, duration } = await loadConfig(args.config);
|
|
38
46
|
|
|
39
|
-
if (!
|
|
47
|
+
if (!flags.json) {
|
|
40
48
|
printKV('Config', path.relative(process.cwd(), absolutePath));
|
|
41
49
|
printKV('Load time', `${duration}ms`);
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
// 2.
|
|
45
|
-
if (!
|
|
46
|
-
const
|
|
52
|
+
// 2. Normalize map-formatted stack definition and validate against Protocol
|
|
53
|
+
if (!flags.json) printStep('Validating protocol compliance...');
|
|
54
|
+
const normalized = normalizeStackInput(config as Record<string, unknown>);
|
|
55
|
+
const result = ObjectStackDefinitionSchema.safeParse(normalized);
|
|
47
56
|
|
|
48
57
|
if (!result.success) {
|
|
49
|
-
if (
|
|
58
|
+
if (flags.json) {
|
|
50
59
|
console.log(JSON.stringify({ success: false, errors: (result.error as unknown as ZodError).issues }));
|
|
51
|
-
|
|
60
|
+
this.exit(1);
|
|
52
61
|
}
|
|
53
62
|
console.log('');
|
|
54
63
|
printError('Validation failed');
|
|
55
64
|
formatZodErrors(result.error as unknown as ZodError);
|
|
56
|
-
|
|
65
|
+
this.exit(1);
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
// 3. Generate Artifact
|
|
60
|
-
if (!
|
|
61
|
-
const output =
|
|
69
|
+
if (!flags.json) printStep('Writing artifact...');
|
|
70
|
+
const output = flags.output!;
|
|
62
71
|
const artifactPath = path.resolve(process.cwd(), output);
|
|
63
72
|
const artifactDir = path.dirname(artifactPath);
|
|
64
73
|
|
|
@@ -72,7 +81,7 @@ export const compileCommand = new Command('compile')
|
|
|
72
81
|
const sizeKB = (jsonContent.length / 1024).toFixed(1);
|
|
73
82
|
const stats = collectMetadataStats(config);
|
|
74
83
|
|
|
75
|
-
if (
|
|
84
|
+
if (flags.json) {
|
|
76
85
|
console.log(JSON.stringify({
|
|
77
86
|
success: true,
|
|
78
87
|
output: artifactPath,
|
|
@@ -93,12 +102,13 @@ export const compileCommand = new Command('compile')
|
|
|
93
102
|
console.log('');
|
|
94
103
|
|
|
95
104
|
} catch (error: any) {
|
|
96
|
-
if (
|
|
105
|
+
if (flags.json) {
|
|
97
106
|
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
98
|
-
|
|
107
|
+
this.exit(1);
|
|
99
108
|
}
|
|
100
109
|
console.log('');
|
|
101
110
|
printError(error.message || String(error));
|
|
102
|
-
|
|
111
|
+
this.error(error.message || String(error));
|
|
103
112
|
}
|
|
104
|
-
}
|
|
113
|
+
}
|
|
114
|
+
}
|
package/src/commands/create.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import path from 'path';
|
|
@@ -182,37 +182,46 @@ function toCamelCase(str: string): string {
|
|
|
182
182
|
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
export
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
185
|
+
export default class Create extends Command {
|
|
186
|
+
static override description = 'Create a new package, plugin, or example from template';
|
|
187
|
+
|
|
188
|
+
static override args = {
|
|
189
|
+
type: Args.string({ description: 'Type of project to create (plugin, example)', required: true }),
|
|
190
|
+
name: Args.string({ description: 'Name of the project', required: false }),
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
static override flags = {
|
|
194
|
+
dir: Flags.string({ char: 'd', description: 'Target directory' }),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
async run(): Promise<void> {
|
|
198
|
+
const { args, flags } = await this.parse(Create);
|
|
199
|
+
|
|
191
200
|
console.log(chalk.bold(`\n📦 ObjectStack Project Creator`));
|
|
192
201
|
console.log(chalk.dim(`-------------------------------`));
|
|
193
202
|
|
|
194
|
-
if (!templates[type as keyof typeof templates]) {
|
|
195
|
-
console.error(chalk.red(`\n❌ Unknown type: ${type}`));
|
|
203
|
+
if (!templates[args.type as keyof typeof templates]) {
|
|
204
|
+
console.error(chalk.red(`\n❌ Unknown type: ${args.type}`));
|
|
196
205
|
console.log(chalk.dim('Available types: plugin, example'));
|
|
197
206
|
process.exit(1);
|
|
198
207
|
}
|
|
199
208
|
|
|
200
|
-
if (!name) {
|
|
209
|
+
if (!args.name) {
|
|
201
210
|
console.error(chalk.red('\n❌ Project name is required'));
|
|
202
|
-
console.log(chalk.dim(`Usage: objectstack create ${type} <name>`));
|
|
211
|
+
console.log(chalk.dim(`Usage: objectstack create ${args.type} <name>`));
|
|
203
212
|
process.exit(1);
|
|
204
213
|
}
|
|
205
214
|
|
|
206
|
-
const template = templates[type as keyof typeof templates];
|
|
215
|
+
const template = templates[args.type as keyof typeof templates];
|
|
207
216
|
const cwd = process.cwd();
|
|
208
217
|
|
|
209
218
|
// Determine target directory
|
|
210
219
|
let targetDir: string;
|
|
211
|
-
if (
|
|
212
|
-
targetDir = path.resolve(cwd,
|
|
220
|
+
if (flags.dir) {
|
|
221
|
+
targetDir = path.resolve(cwd, flags.dir);
|
|
213
222
|
} else {
|
|
214
|
-
const baseDir = type === 'plugin' ? 'packages/plugins' : 'examples';
|
|
215
|
-
const projectName = type === 'plugin' ? `plugin-${name}` : name;
|
|
223
|
+
const baseDir = args.type === 'plugin' ? 'packages/plugins' : 'examples';
|
|
224
|
+
const projectName = args.type === 'plugin' ? `plugin-${args.name}` : args.name;
|
|
216
225
|
targetDir = path.join(cwd, baseDir, projectName);
|
|
217
226
|
}
|
|
218
227
|
|
|
@@ -222,7 +231,7 @@ export const createCommand = new Command('create')
|
|
|
222
231
|
process.exit(1);
|
|
223
232
|
}
|
|
224
233
|
|
|
225
|
-
console.log(`📁 Creating ${type}: ${chalk.blue(name)}`);
|
|
234
|
+
console.log(`📁 Creating ${args.type}: ${chalk.blue(args.name)}`);
|
|
226
235
|
console.log(`📂 Location: ${chalk.dim(targetDir)}`);
|
|
227
236
|
console.log('');
|
|
228
237
|
|
|
@@ -239,7 +248,7 @@ export const createCommand = new Command('create')
|
|
|
239
248
|
fs.mkdirSync(dir, { recursive: true });
|
|
240
249
|
}
|
|
241
250
|
|
|
242
|
-
const content = contentFn(name);
|
|
251
|
+
const content = contentFn(args.name);
|
|
243
252
|
const fileContent = typeof content === 'string'
|
|
244
253
|
? content
|
|
245
254
|
: JSON.stringify(content, null, 2);
|
|
@@ -268,4 +277,5 @@ export const createCommand = new Command('create')
|
|
|
268
277
|
|
|
269
278
|
process.exit(1);
|
|
270
279
|
}
|
|
271
|
-
}
|
|
280
|
+
}
|
|
281
|
+
}
|
package/src/commands/dev.ts
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { execSync, spawn } from 'child_process';
|
|
6
6
|
import fs from 'fs';
|
|
7
7
|
import path from 'path';
|
|
8
8
|
import { printHeader, printKV, printStep, printError } from '../utils/format.js';
|
|
9
9
|
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
export default class Dev extends Command {
|
|
11
|
+
static override description = 'Start development mode with hot-reload';
|
|
12
|
+
|
|
13
|
+
static override args = {
|
|
14
|
+
package: Args.string({ description: 'Package name or filter pattern', default: 'all', required: false }),
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
static override flags = {
|
|
18
|
+
watch: Flags.boolean({ char: 'w', description: 'Enable watch mode (default)', default: true }),
|
|
19
|
+
ui: Flags.boolean({ description: 'Enable Studio UI at /_studio/' }),
|
|
20
|
+
verbose: Flags.boolean({ char: 'v', description: 'Verbose output' }),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
async run(): Promise<void> {
|
|
24
|
+
const { args, flags } = await this.parse(Dev);
|
|
25
|
+
const packageName = args.package;
|
|
26
|
+
|
|
17
27
|
printHeader('Development Mode');
|
|
18
28
|
|
|
19
29
|
// Check if we are running inside a package (Single Package Mode)
|
|
@@ -28,7 +38,7 @@ export const devCommand = new Command('dev')
|
|
|
28
38
|
// usage: objectstack serve --dev
|
|
29
39
|
const binPath = process.argv[1]; // path to objectstack bin
|
|
30
40
|
|
|
31
|
-
const child = spawn(process.execPath, [binPath, 'serve', '--dev', ...(
|
|
41
|
+
const child = spawn(process.execPath, [binPath, 'serve', '--dev', ...(flags.ui ? ['--ui'] : []), ...(flags.verbose ? ['--verbose'] : [])], {
|
|
32
42
|
stdio: 'inherit',
|
|
33
43
|
env: { ...process.env, NODE_ENV: 'development' }
|
|
34
44
|
});
|
|
@@ -69,4 +79,5 @@ export const devCommand = new Command('dev')
|
|
|
69
79
|
printError(`Development mode failed: ${error.message || error}`);
|
|
70
80
|
process.exit(1);
|
|
71
81
|
}
|
|
72
|
-
}
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/commands/diff.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import { loadConfig } from '../utils/config.js';
|
|
6
6
|
import {
|
|
@@ -153,19 +153,27 @@ function diffNamedArrays(
|
|
|
153
153
|
|
|
154
154
|
// ─── Command ────────────────────────────────────────────────────────
|
|
155
155
|
|
|
156
|
-
export
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
export default class Diff extends Command {
|
|
157
|
+
static override description = 'Compare two ObjectStack configurations and detect breaking changes';
|
|
158
|
+
|
|
159
|
+
static override args = {
|
|
160
|
+
before: Args.string({ description: 'Path to the "before" config file', required: false }),
|
|
161
|
+
after: Args.string({ description: 'Path to the "after" config file', required: false }),
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
static override flags = {
|
|
165
|
+
before: Flags.string({ description: 'Path to the "before" config (alternative)' }),
|
|
166
|
+
after: Flags.string({ description: 'Path to the "after" config (alternative)' }),
|
|
167
|
+
json: Flags.boolean({ description: 'Output as JSON' }),
|
|
168
|
+
'breaking-only': Flags.boolean({ description: 'Show only breaking changes' }),
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
async run(): Promise<void> {
|
|
172
|
+
const { args, flags } = await this.parse(Diff);
|
|
165
173
|
const timer = createTimer();
|
|
166
174
|
|
|
167
|
-
const beforePath: string | undefined =
|
|
168
|
-
const afterPath: string | undefined =
|
|
175
|
+
const beforePath: string | undefined = args.before || flags.before;
|
|
176
|
+
const afterPath: string | undefined = args.after || flags.after;
|
|
169
177
|
|
|
170
178
|
if (!beforePath || !afterPath) {
|
|
171
179
|
printError('Two config file paths are required.');
|
|
@@ -175,7 +183,7 @@ export const diffCommand = new Command('diff')
|
|
|
175
183
|
process.exit(1);
|
|
176
184
|
}
|
|
177
185
|
|
|
178
|
-
if (!
|
|
186
|
+
if (!flags.json) {
|
|
179
187
|
printHeader('Diff');
|
|
180
188
|
printStep('Loading configurations...');
|
|
181
189
|
}
|
|
@@ -184,7 +192,7 @@ export const diffCommand = new Command('diff')
|
|
|
184
192
|
const { config: beforeConfig } = await loadConfig(beforePath);
|
|
185
193
|
const { config: afterConfig } = await loadConfig(afterPath);
|
|
186
194
|
|
|
187
|
-
if (!
|
|
195
|
+
if (!flags.json) {
|
|
188
196
|
printInfo(`Before: ${chalk.white(beforePath)}`);
|
|
189
197
|
printInfo(`After: ${chalk.white(afterPath)}`);
|
|
190
198
|
}
|
|
@@ -215,14 +223,14 @@ export const diffCommand = new Command('diff')
|
|
|
215
223
|
}
|
|
216
224
|
|
|
217
225
|
// ── Filter ──
|
|
218
|
-
const diffs =
|
|
226
|
+
const diffs = flags['breaking-only']
|
|
219
227
|
? allDiffs.filter((d) => d.breaking)
|
|
220
228
|
: allDiffs;
|
|
221
229
|
|
|
222
230
|
const breakingCount = allDiffs.filter((d) => d.breaking).length;
|
|
223
231
|
|
|
224
232
|
// ── Output ──
|
|
225
|
-
if (
|
|
233
|
+
if (flags.json) {
|
|
226
234
|
console.log(JSON.stringify({
|
|
227
235
|
before: beforePath,
|
|
228
236
|
after: afterPath,
|
|
@@ -237,7 +245,7 @@ export const diffCommand = new Command('diff')
|
|
|
237
245
|
console.log('');
|
|
238
246
|
|
|
239
247
|
if (diffs.length === 0) {
|
|
240
|
-
printSuccess(
|
|
248
|
+
printSuccess(flags['breaking-only']
|
|
241
249
|
? 'No breaking changes detected.'
|
|
242
250
|
: 'No changes detected.');
|
|
243
251
|
console.log('');
|
|
@@ -274,7 +282,7 @@ export const diffCommand = new Command('diff')
|
|
|
274
282
|
console.log('');
|
|
275
283
|
|
|
276
284
|
} catch (error: any) {
|
|
277
|
-
if (
|
|
285
|
+
if (flags.json) {
|
|
278
286
|
console.log(JSON.stringify({ error: error.message }));
|
|
279
287
|
process.exit(1);
|
|
280
288
|
}
|
|
@@ -282,4 +290,5 @@ export const diffCommand = new Command('diff')
|
|
|
282
290
|
printError(error.message || String(error));
|
|
283
291
|
process.exit(1);
|
|
284
292
|
}
|
|
285
|
-
}
|
|
293
|
+
}
|
|
294
|
+
}
|
package/src/commands/doctor.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Command, Flags } from '@oclif/core';
|
|
4
4
|
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
|
|
|
@@ -298,11 +299,17 @@ function scanDeprecatedPatterns(dir: string): Array<{ file: string; line: number
|
|
|
298
299
|
|
|
299
300
|
// ─── Command ────────────────────────────────────────────────────────
|
|
300
301
|
|
|
301
|
-
export
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
302
|
+
export default class Doctor extends Command {
|
|
303
|
+
static override description = 'Check development environment and configuration health';
|
|
304
|
+
|
|
305
|
+
static override flags = {
|
|
306
|
+
verbose: Flags.boolean({ char: 'v', description: 'Show detailed information' }),
|
|
307
|
+
'scan-deprecations': Flags.boolean({ description: 'Scan for deprecated ObjectStack patterns' }),
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
async run(): Promise<void> {
|
|
311
|
+
const { flags } = await this.parse(Doctor);
|
|
312
|
+
|
|
306
313
|
printHeader('Environment Health Check');
|
|
307
314
|
|
|
308
315
|
const results: HealthCheckResult[] = [];
|
|
@@ -438,7 +445,7 @@ export const doctorCommand = new Command('doctor')
|
|
|
438
445
|
printError(`${padded} ${result.message}`);
|
|
439
446
|
}
|
|
440
447
|
|
|
441
|
-
if (result.fix && (
|
|
448
|
+
if (result.fix && (flags.verbose || result.status === 'error')) {
|
|
442
449
|
console.log(chalk.dim(` → ${result.fix}`));
|
|
443
450
|
}
|
|
444
451
|
|
|
@@ -476,7 +483,8 @@ export const doctorCommand = new Command('doctor')
|
|
|
476
483
|
if (configExists()) {
|
|
477
484
|
printStep('Loading configuration for analysis...');
|
|
478
485
|
try {
|
|
479
|
-
const { config } = await loadConfig();
|
|
486
|
+
const { config: rawConfig } = await loadConfig();
|
|
487
|
+
const config: any = normalizeStackInput(rawConfig as Record<string, unknown>);
|
|
480
488
|
|
|
481
489
|
// Circular dependency detection
|
|
482
490
|
if (Array.isArray(config.objects) && config.objects.length > 0) {
|
|
@@ -524,7 +532,7 @@ export const doctorCommand = new Command('doctor')
|
|
|
524
532
|
}
|
|
525
533
|
|
|
526
534
|
// ── Deprecation Pattern Scan ─────────────────────────────────────
|
|
527
|
-
if (
|
|
535
|
+
if (flags['scan-deprecations']) {
|
|
528
536
|
printStep('Scanning for deprecated ObjectStack patterns...');
|
|
529
537
|
const scanDir = path.join(cwd, 'src');
|
|
530
538
|
const deprecations = scanDeprecatedPatterns(scanDir);
|
|
@@ -532,7 +540,7 @@ export const doctorCommand = new Command('doctor')
|
|
|
532
540
|
hasWarnings = true;
|
|
533
541
|
for (const dep of deprecations) {
|
|
534
542
|
printWarning(`${dep.file}:${dep.line} — ${dep.description}`);
|
|
535
|
-
if (
|
|
543
|
+
if (flags.verbose) {
|
|
536
544
|
console.log(chalk.dim(` → ${dep.replacement}`));
|
|
537
545
|
}
|
|
538
546
|
}
|
|
@@ -560,4 +568,5 @@ export const doctorCommand = new Command('doctor')
|
|
|
560
568
|
}
|
|
561
569
|
|
|
562
570
|
console.log('');
|
|
563
|
-
}
|
|
571
|
+
}
|
|
572
|
+
}
|
package/src/commands/explain.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import {
|
|
6
6
|
printHeader,
|
|
@@ -314,15 +314,24 @@ const SCHEMAS: Record<string, SchemaInfo> = {
|
|
|
314
314
|
|
|
315
315
|
// ─── Command ────────────────────────────────────────────────────────
|
|
316
316
|
|
|
317
|
-
export
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
317
|
+
export default class Explain extends Command {
|
|
318
|
+
static override description = 'Display human-readable explanation of an ObjectStack schema';
|
|
319
|
+
|
|
320
|
+
static override args = {
|
|
321
|
+
schema: Args.string({ description: 'Schema name (e.g., object, field, view, flow, agent, app)', required: false }),
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
static override flags = {
|
|
325
|
+
json: Flags.boolean({ description: 'Output as JSON' }),
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
async run(): Promise<void> {
|
|
329
|
+
const { args, flags } = await this.parse(Explain);
|
|
330
|
+
const schemaName = args.schema;
|
|
322
331
|
|
|
323
332
|
// ── No argument: list all schemas ──
|
|
324
333
|
if (!schemaName) {
|
|
325
|
-
if (
|
|
334
|
+
if (flags.json) {
|
|
326
335
|
console.log(JSON.stringify({
|
|
327
336
|
schemas: Object.entries(SCHEMAS).map(([key, s]) => ({
|
|
328
337
|
name: key,
|
|
@@ -347,7 +356,7 @@ export const explainCommand = new Command('explain')
|
|
|
347
356
|
// ── Lookup schema ──
|
|
348
357
|
const schema = SCHEMAS[schemaName.toLowerCase()];
|
|
349
358
|
if (!schema) {
|
|
350
|
-
if (
|
|
359
|
+
if (flags.json) {
|
|
351
360
|
console.log(JSON.stringify({ error: `Unknown schema: ${schemaName}` }));
|
|
352
361
|
process.exit(1);
|
|
353
362
|
}
|
|
@@ -359,7 +368,7 @@ export const explainCommand = new Command('explain')
|
|
|
359
368
|
}
|
|
360
369
|
|
|
361
370
|
// ── JSON output ──
|
|
362
|
-
if (
|
|
371
|
+
if (flags.json) {
|
|
363
372
|
console.log(JSON.stringify(schema, null, 2));
|
|
364
373
|
return;
|
|
365
374
|
}
|
|
@@ -399,4 +408,5 @@ export const explainCommand = new Command('explain')
|
|
|
399
408
|
// Documentation link
|
|
400
409
|
printKV(' Docs', `https://objectstack.dev/docs/${schema.docsPath}`);
|
|
401
410
|
console.log('');
|
|
402
|
-
}
|
|
411
|
+
}
|
|
412
|
+
}
|