@objectstack/cli 2.0.7 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +10 -6
- package/CHANGELOG.md +17 -0
- package/dist/bin.js +388 -464
- package/dist/chunk-CSHQEILI.js +246 -0
- package/dist/chunk-Q74JNWKD.js +248 -0
- package/dist/config-A7BN6UIT.js +11 -0
- package/dist/config-UN34WBHT.js +10 -0
- package/dist/index.js +373 -448
- package/package.json +9 -9
- package/src/commands/generate.ts +181 -3
package/dist/index.js
CHANGED
|
@@ -1,237 +1,26 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collectMetadataStats,
|
|
3
|
+
createTimer,
|
|
4
|
+
formatZodErrors,
|
|
5
|
+
loadConfig,
|
|
6
|
+
printError,
|
|
7
|
+
printHeader,
|
|
8
|
+
printInfo,
|
|
9
|
+
printKV,
|
|
10
|
+
printMetadataStats,
|
|
11
|
+
printServerReady,
|
|
12
|
+
printStep,
|
|
13
|
+
printSuccess,
|
|
14
|
+
printWarning,
|
|
15
|
+
resolveConfigPath
|
|
16
|
+
} from "./chunk-CSHQEILI.js";
|
|
17
|
+
|
|
1
18
|
// src/commands/compile.ts
|
|
2
19
|
import { Command } from "commander";
|
|
3
|
-
import path2 from "path";
|
|
4
|
-
import fs2 from "fs";
|
|
5
|
-
import chalk3 from "chalk";
|
|
6
|
-
import { ObjectStackDefinitionSchema } from "@objectstack/spec";
|
|
7
|
-
|
|
8
|
-
// src/utils/config.ts
|
|
9
20
|
import path from "path";
|
|
10
21
|
import fs from "fs";
|
|
11
|
-
import chalk2 from "chalk";
|
|
12
|
-
import { bundleRequire } from "bundle-require";
|
|
13
|
-
|
|
14
|
-
// src/utils/format.ts
|
|
15
22
|
import chalk from "chalk";
|
|
16
|
-
|
|
17
|
-
console.log(chalk.bold(`
|
|
18
|
-
\u25C6 ${title}`));
|
|
19
|
-
console.log(chalk.dim("\u2500".repeat(40)));
|
|
20
|
-
}
|
|
21
|
-
function printKV(key, value, icon) {
|
|
22
|
-
const prefix = icon ? `${icon} ` : " ";
|
|
23
|
-
console.log(`${prefix}${chalk.dim(key + ":")} ${chalk.white(String(value))}`);
|
|
24
|
-
}
|
|
25
|
-
function printSuccess(msg) {
|
|
26
|
-
console.log(chalk.green(` \u2713 ${msg}`));
|
|
27
|
-
}
|
|
28
|
-
function printWarning(msg) {
|
|
29
|
-
console.log(chalk.yellow(` \u26A0 ${msg}`));
|
|
30
|
-
}
|
|
31
|
-
function printError(msg) {
|
|
32
|
-
console.log(chalk.red(` \u2717 ${msg}`));
|
|
33
|
-
}
|
|
34
|
-
function printInfo(msg) {
|
|
35
|
-
console.log(chalk.blue(` \u2139 ${msg}`));
|
|
36
|
-
}
|
|
37
|
-
function printStep(msg) {
|
|
38
|
-
console.log(chalk.yellow(` \u2192 ${msg}`));
|
|
39
|
-
}
|
|
40
|
-
function createTimer() {
|
|
41
|
-
const start = Date.now();
|
|
42
|
-
return {
|
|
43
|
-
elapsed: () => Date.now() - start,
|
|
44
|
-
display: () => `${Date.now() - start}ms`
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function formatZodErrors(error) {
|
|
48
|
-
const issues = error.issues || error.errors || [];
|
|
49
|
-
if (issues.length === 0) {
|
|
50
|
-
console.log(chalk.red(" Unknown validation error"));
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
54
|
-
for (const issue of issues) {
|
|
55
|
-
const topPath = issue.path?.[0] || "_root";
|
|
56
|
-
if (!grouped.has(String(topPath))) {
|
|
57
|
-
grouped.set(String(topPath), []);
|
|
58
|
-
}
|
|
59
|
-
grouped.get(String(topPath)).push(issue);
|
|
60
|
-
}
|
|
61
|
-
for (const [section, sectionIssues] of grouped) {
|
|
62
|
-
console.log(chalk.bold.red(`
|
|
63
|
-
${section}:`));
|
|
64
|
-
for (const issue of sectionIssues) {
|
|
65
|
-
const path12 = issue.path?.join(".") || "";
|
|
66
|
-
const code = issue.code || "";
|
|
67
|
-
const msg = issue.message || "";
|
|
68
|
-
console.log(chalk.red(` \u2717 ${path12}`));
|
|
69
|
-
console.log(chalk.dim(` ${code}: ${msg}`));
|
|
70
|
-
if (issue.expected) {
|
|
71
|
-
console.log(chalk.dim(` expected: ${chalk.green(issue.expected)}`));
|
|
72
|
-
}
|
|
73
|
-
if (issue.received) {
|
|
74
|
-
console.log(chalk.dim(` received: ${chalk.red(issue.received)}`));
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
console.log("");
|
|
79
|
-
console.log(chalk.dim(` ${issues.length} validation error(s) total`));
|
|
80
|
-
}
|
|
81
|
-
function collectMetadataStats(config) {
|
|
82
|
-
const count = (arr) => Array.isArray(arr) ? arr.length : 0;
|
|
83
|
-
let fields = 0;
|
|
84
|
-
if (Array.isArray(config.objects)) {
|
|
85
|
-
for (const obj of config.objects) {
|
|
86
|
-
if (obj.fields && typeof obj.fields === "object") {
|
|
87
|
-
fields += Object.keys(obj.fields).length;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
objects: count(config.objects),
|
|
93
|
-
objectExtensions: count(config.objectExtensions),
|
|
94
|
-
fields,
|
|
95
|
-
views: count(config.views),
|
|
96
|
-
pages: count(config.pages),
|
|
97
|
-
apps: count(config.apps),
|
|
98
|
-
dashboards: count(config.dashboards),
|
|
99
|
-
reports: count(config.reports),
|
|
100
|
-
actions: count(config.actions),
|
|
101
|
-
flows: count(config.flows),
|
|
102
|
-
workflows: count(config.workflows),
|
|
103
|
-
approvals: count(config.approvals),
|
|
104
|
-
agents: count(config.agents),
|
|
105
|
-
apis: count(config.apis),
|
|
106
|
-
roles: count(config.roles),
|
|
107
|
-
permissions: count(config.permissions),
|
|
108
|
-
themes: count(config.themes),
|
|
109
|
-
datasources: count(config.datasources),
|
|
110
|
-
translations: count(config.translations),
|
|
111
|
-
plugins: count(config.plugins),
|
|
112
|
-
devPlugins: count(config.devPlugins)
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
function printServerReady(opts) {
|
|
116
|
-
const base = `http://localhost:${opts.port}`;
|
|
117
|
-
console.log("");
|
|
118
|
-
console.log(chalk.bold.green(" \u2713 Server is ready"));
|
|
119
|
-
console.log("");
|
|
120
|
-
console.log(chalk.cyan(" \u279C") + chalk.bold(" API: ") + chalk.cyan(base + "/"));
|
|
121
|
-
if (opts.uiEnabled && opts.studioPath) {
|
|
122
|
-
console.log(chalk.cyan(" \u279C") + chalk.bold(" Studio: ") + chalk.cyan(base + opts.studioPath + "/"));
|
|
123
|
-
}
|
|
124
|
-
console.log("");
|
|
125
|
-
console.log(chalk.dim(` Config: ${opts.configFile}`));
|
|
126
|
-
console.log(chalk.dim(` Mode: ${opts.isDev ? "development" : "production"}`));
|
|
127
|
-
console.log(chalk.dim(` Plugins: ${opts.pluginCount} loaded`));
|
|
128
|
-
if (opts.pluginNames && opts.pluginNames.length > 0) {
|
|
129
|
-
console.log(chalk.dim(` ${opts.pluginNames.join(", ")}`));
|
|
130
|
-
}
|
|
131
|
-
console.log("");
|
|
132
|
-
console.log(chalk.dim(" Press Ctrl+C to stop"));
|
|
133
|
-
console.log("");
|
|
134
|
-
}
|
|
135
|
-
function printMetadataStats(stats) {
|
|
136
|
-
const sections = [
|
|
137
|
-
{
|
|
138
|
-
label: "Data",
|
|
139
|
-
items: [
|
|
140
|
-
["Objects", stats.objects],
|
|
141
|
-
["Fields", stats.fields],
|
|
142
|
-
["Extensions", stats.objectExtensions],
|
|
143
|
-
["Datasources", stats.datasources]
|
|
144
|
-
]
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
label: "UI",
|
|
148
|
-
items: [
|
|
149
|
-
["Apps", stats.apps],
|
|
150
|
-
["Views", stats.views],
|
|
151
|
-
["Pages", stats.pages],
|
|
152
|
-
["Dashboards", stats.dashboards],
|
|
153
|
-
["Reports", stats.reports],
|
|
154
|
-
["Actions", stats.actions],
|
|
155
|
-
["Themes", stats.themes]
|
|
156
|
-
]
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
label: "Logic",
|
|
160
|
-
items: [
|
|
161
|
-
["Flows", stats.flows],
|
|
162
|
-
["Workflows", stats.workflows],
|
|
163
|
-
["Approvals", stats.approvals],
|
|
164
|
-
["Agents", stats.agents],
|
|
165
|
-
["APIs", stats.apis]
|
|
166
|
-
]
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
label: "Security",
|
|
170
|
-
items: [
|
|
171
|
-
["Roles", stats.roles],
|
|
172
|
-
["Permissions", stats.permissions]
|
|
173
|
-
]
|
|
174
|
-
}
|
|
175
|
-
];
|
|
176
|
-
for (const section of sections) {
|
|
177
|
-
const nonZero = section.items.filter(([, v]) => v > 0);
|
|
178
|
-
if (nonZero.length === 0) continue;
|
|
179
|
-
const line = nonZero.map(([k, v]) => `${chalk.white(v)} ${chalk.dim(k)}`).join(" ");
|
|
180
|
-
console.log(` ${chalk.bold(section.label + ":")} ${line}`);
|
|
181
|
-
}
|
|
182
|
-
if (stats.plugins > 0 || stats.devPlugins > 0) {
|
|
183
|
-
const parts = [];
|
|
184
|
-
if (stats.plugins > 0) parts.push(`${stats.plugins} plugins`);
|
|
185
|
-
if (stats.devPlugins > 0) parts.push(`${stats.devPlugins} devPlugins`);
|
|
186
|
-
console.log(` ${chalk.bold("Runtime:")} ${chalk.dim(parts.join(", "))}`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// src/utils/config.ts
|
|
191
|
-
function resolveConfigPath(source) {
|
|
192
|
-
if (source) {
|
|
193
|
-
const abs = path.resolve(process.cwd(), source);
|
|
194
|
-
if (!fs.existsSync(abs)) {
|
|
195
|
-
printError(`Config file not found: ${chalk2.white(abs)}`);
|
|
196
|
-
console.log("");
|
|
197
|
-
console.log(chalk2.dim(" Hint: Run this command from a directory with objectstack.config.ts"));
|
|
198
|
-
console.log(chalk2.dim(" Or specify the path: objectstack <command> path/to/config.ts"));
|
|
199
|
-
process.exit(1);
|
|
200
|
-
}
|
|
201
|
-
return abs;
|
|
202
|
-
}
|
|
203
|
-
const candidates = [
|
|
204
|
-
"objectstack.config.ts",
|
|
205
|
-
"objectstack.config.js",
|
|
206
|
-
"objectstack.config.mjs"
|
|
207
|
-
];
|
|
208
|
-
for (const candidate of candidates) {
|
|
209
|
-
const abs = path.resolve(process.cwd(), candidate);
|
|
210
|
-
if (fs.existsSync(abs)) return abs;
|
|
211
|
-
}
|
|
212
|
-
printError("No objectstack.config.{ts,js,mjs} found in current directory");
|
|
213
|
-
console.log("");
|
|
214
|
-
console.log(chalk2.dim(" Hint: Run `objectstack init` to create a new project"));
|
|
215
|
-
process.exit(1);
|
|
216
|
-
}
|
|
217
|
-
async function loadConfig(source) {
|
|
218
|
-
const absolutePath = resolveConfigPath(source);
|
|
219
|
-
const start = Date.now();
|
|
220
|
-
const { mod } = await bundleRequire({
|
|
221
|
-
filepath: absolutePath
|
|
222
|
-
});
|
|
223
|
-
const config = mod.default || mod;
|
|
224
|
-
if (!config) {
|
|
225
|
-
throw new Error(`No default export found in ${path.basename(absolutePath)}`);
|
|
226
|
-
}
|
|
227
|
-
return {
|
|
228
|
-
config,
|
|
229
|
-
absolutePath,
|
|
230
|
-
duration: Date.now() - start
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// src/commands/compile.ts
|
|
23
|
+
import { ObjectStackDefinitionSchema } from "@objectstack/spec";
|
|
235
24
|
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) => {
|
|
236
25
|
const timer = createTimer();
|
|
237
26
|
if (!options.json) {
|
|
@@ -241,7 +30,7 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
|
|
|
241
30
|
if (!options.json) printStep("Loading configuration...");
|
|
242
31
|
const { config, absolutePath, duration } = await loadConfig(configPath);
|
|
243
32
|
if (!options.json) {
|
|
244
|
-
printKV("Config",
|
|
33
|
+
printKV("Config", path.relative(process.cwd(), absolutePath));
|
|
245
34
|
printKV("Load time", `${duration}ms`);
|
|
246
35
|
}
|
|
247
36
|
if (!options.json) printStep("Validating protocol compliance...");
|
|
@@ -258,13 +47,13 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
|
|
|
258
47
|
}
|
|
259
48
|
if (!options.json) printStep("Writing artifact...");
|
|
260
49
|
const output = options.output;
|
|
261
|
-
const artifactPath =
|
|
262
|
-
const artifactDir =
|
|
263
|
-
if (!
|
|
264
|
-
|
|
50
|
+
const artifactPath = path.resolve(process.cwd(), output);
|
|
51
|
+
const artifactDir = path.dirname(artifactPath);
|
|
52
|
+
if (!fs.existsSync(artifactDir)) {
|
|
53
|
+
fs.mkdirSync(artifactDir, { recursive: true });
|
|
265
54
|
}
|
|
266
55
|
const jsonContent = JSON.stringify(result.data, null, 2);
|
|
267
|
-
|
|
56
|
+
fs.writeFileSync(artifactPath, jsonContent);
|
|
268
57
|
const sizeKB = (jsonContent.length / 1024).toFixed(1);
|
|
269
58
|
const stats = collectMetadataStats(config);
|
|
270
59
|
if (options.json) {
|
|
@@ -278,11 +67,11 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
|
|
|
278
67
|
return;
|
|
279
68
|
}
|
|
280
69
|
console.log("");
|
|
281
|
-
printSuccess(`Build complete ${
|
|
70
|
+
printSuccess(`Build complete ${chalk.dim(`(${timer.display()})`)}`);
|
|
282
71
|
console.log("");
|
|
283
72
|
printMetadataStats(stats);
|
|
284
73
|
console.log("");
|
|
285
|
-
printKV("Artifact", `${output} ${
|
|
74
|
+
printKV("Artifact", `${output} ${chalk.dim(`(${sizeKB} KB`)})`);
|
|
286
75
|
console.log("");
|
|
287
76
|
} catch (error) {
|
|
288
77
|
if (options.json) {
|
|
@@ -297,7 +86,7 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
|
|
|
297
86
|
|
|
298
87
|
// src/commands/validate.ts
|
|
299
88
|
import { Command as Command2 } from "commander";
|
|
300
|
-
import
|
|
89
|
+
import chalk2 from "chalk";
|
|
301
90
|
import { ObjectStackDefinitionSchema as ObjectStackDefinitionSchema2 } from "@objectstack/spec";
|
|
302
91
|
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) => {
|
|
303
92
|
const timer = createTimer();
|
|
@@ -351,12 +140,12 @@ var validateCommand = new Command2("validate").description("Validate ObjectStack
|
|
|
351
140
|
warnings.push("Missing manifest.namespace \u2014 required for multi-app hosting");
|
|
352
141
|
}
|
|
353
142
|
console.log("");
|
|
354
|
-
printSuccess(`Validation passed ${
|
|
143
|
+
printSuccess(`Validation passed ${chalk2.dim(`(${timer.display()})`)}`);
|
|
355
144
|
console.log("");
|
|
356
145
|
if (config.manifest) {
|
|
357
|
-
console.log(` ${
|
|
146
|
+
console.log(` ${chalk2.bold(config.manifest.name || config.manifest.id || "Unnamed")} ${chalk2.dim(`v${config.manifest.version || "0.0.0"}`)}`);
|
|
358
147
|
if (config.manifest.description) {
|
|
359
|
-
console.log(
|
|
148
|
+
console.log(chalk2.dim(` ${config.manifest.description}`));
|
|
360
149
|
}
|
|
361
150
|
console.log("");
|
|
362
151
|
}
|
|
@@ -364,7 +153,7 @@ var validateCommand = new Command2("validate").description("Validate ObjectStack
|
|
|
364
153
|
if (warnings.length > 0) {
|
|
365
154
|
console.log("");
|
|
366
155
|
for (const w of warnings) {
|
|
367
|
-
console.log(
|
|
156
|
+
console.log(chalk2.yellow(` \u26A0 ${w}`));
|
|
368
157
|
}
|
|
369
158
|
if (options.strict) {
|
|
370
159
|
console.log("");
|
|
@@ -390,7 +179,7 @@ var validateCommand = new Command2("validate").description("Validate ObjectStack
|
|
|
390
179
|
|
|
391
180
|
// src/commands/info.ts
|
|
392
181
|
import { Command as Command3 } from "commander";
|
|
393
|
-
import
|
|
182
|
+
import chalk3 from "chalk";
|
|
394
183
|
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) => {
|
|
395
184
|
const timer = createTimer();
|
|
396
185
|
if (!options.json) {
|
|
@@ -416,9 +205,9 @@ var infoCommand = new Command3("info").description("Display metadata summary of
|
|
|
416
205
|
if (config.manifest) {
|
|
417
206
|
const m = config.manifest;
|
|
418
207
|
console.log("");
|
|
419
|
-
console.log(` ${
|
|
420
|
-
if (m.id) console.log(
|
|
421
|
-
if (m.description) console.log(
|
|
208
|
+
console.log(` ${chalk3.bold(m.name || m.id || "Unnamed")} ${chalk3.dim(`v${m.version || "0.0.0"}`)}`);
|
|
209
|
+
if (m.id) console.log(chalk3.dim(` ${m.id}`));
|
|
210
|
+
if (m.description) console.log(chalk3.dim(` ${m.description}`));
|
|
422
211
|
if (m.namespace) printKV(" Namespace", m.namespace);
|
|
423
212
|
if (m.type) printKV(" Type", m.type);
|
|
424
213
|
}
|
|
@@ -426,35 +215,35 @@ var infoCommand = new Command3("info").description("Display metadata summary of
|
|
|
426
215
|
printMetadataStats(stats);
|
|
427
216
|
if (config.objects && config.objects.length > 0) {
|
|
428
217
|
console.log("");
|
|
429
|
-
console.log(
|
|
218
|
+
console.log(chalk3.bold(" Objects:"));
|
|
430
219
|
for (const obj of config.objects) {
|
|
431
220
|
const fieldCount = obj.fields ? Object.keys(obj.fields).length : 0;
|
|
432
221
|
const ownership = obj.ownership || "own";
|
|
433
222
|
console.log(
|
|
434
|
-
` ${
|
|
223
|
+
` ${chalk3.cyan(obj.name || "?")}` + chalk3.dim(` (${fieldCount} fields, ${ownership})`) + (obj.label ? chalk3.dim(` \u2014 ${obj.label}`) : "")
|
|
435
224
|
);
|
|
436
225
|
}
|
|
437
226
|
}
|
|
438
227
|
if (config.agents && config.agents.length > 0) {
|
|
439
228
|
console.log("");
|
|
440
|
-
console.log(
|
|
229
|
+
console.log(chalk3.bold(" Agents:"));
|
|
441
230
|
for (const agent of config.agents) {
|
|
442
231
|
console.log(
|
|
443
|
-
` ${
|
|
232
|
+
` ${chalk3.magenta(agent.name || "?")}` + (agent.role ? chalk3.dim(` \u2014 ${agent.role}`) : "")
|
|
444
233
|
);
|
|
445
234
|
}
|
|
446
235
|
}
|
|
447
236
|
if (config.apps && config.apps.length > 0) {
|
|
448
237
|
console.log("");
|
|
449
|
-
console.log(
|
|
238
|
+
console.log(chalk3.bold(" Apps:"));
|
|
450
239
|
for (const app of config.apps) {
|
|
451
240
|
console.log(
|
|
452
|
-
` ${
|
|
241
|
+
` ${chalk3.green(app.name || "?")}` + (app.label ? chalk3.dim(` \u2014 ${app.label}`) : "")
|
|
453
242
|
);
|
|
454
243
|
}
|
|
455
244
|
}
|
|
456
245
|
console.log("");
|
|
457
|
-
console.log(
|
|
246
|
+
console.log(chalk3.dim(` Loaded in ${duration}ms`));
|
|
458
247
|
console.log("");
|
|
459
248
|
} catch (error) {
|
|
460
249
|
if (options.json) {
|
|
@@ -469,9 +258,9 @@ var infoCommand = new Command3("info").description("Display metadata summary of
|
|
|
469
258
|
|
|
470
259
|
// src/commands/init.ts
|
|
471
260
|
import { Command as Command4 } from "commander";
|
|
472
|
-
import
|
|
473
|
-
import
|
|
474
|
-
import
|
|
261
|
+
import chalk4 from "chalk";
|
|
262
|
+
import fs2 from "fs";
|
|
263
|
+
import path2 from "path";
|
|
475
264
|
var TEMPLATES = {
|
|
476
265
|
app: {
|
|
477
266
|
description: "Full application with objects, views, and actions",
|
|
@@ -636,16 +425,16 @@ function toTitleCase(str) {
|
|
|
636
425
|
var initCommand = new Command4("init").description("Initialize a new ObjectStack project in the current directory").argument("[name]", "Project name (defaults to directory name)").option("-t, --template <template>", "Template: app, plugin, empty", "app").option("--no-install", "Skip dependency installation").action(async (name, options) => {
|
|
637
426
|
printHeader("Init");
|
|
638
427
|
const cwd = process.cwd();
|
|
639
|
-
const projectName = name ||
|
|
428
|
+
const projectName = name || path2.basename(cwd);
|
|
640
429
|
const template = TEMPLATES[options.template];
|
|
641
430
|
if (!template) {
|
|
642
431
|
printError(`Unknown template: ${options.template}`);
|
|
643
|
-
console.log(
|
|
432
|
+
console.log(chalk4.dim(` Available: ${Object.keys(TEMPLATES).join(", ")}`));
|
|
644
433
|
process.exit(1);
|
|
645
434
|
}
|
|
646
|
-
if (
|
|
435
|
+
if (fs2.existsSync(path2.join(cwd, "objectstack.config.ts"))) {
|
|
647
436
|
printError("objectstack.config.ts already exists in this directory");
|
|
648
|
-
console.log(
|
|
437
|
+
console.log(chalk4.dim(" Use `objectstack generate` to add metadata to an existing project"));
|
|
649
438
|
process.exit(1);
|
|
650
439
|
}
|
|
651
440
|
printKV("Project", projectName);
|
|
@@ -654,8 +443,8 @@ var initCommand = new Command4("init").description("Initialize a new ObjectStack
|
|
|
654
443
|
console.log("");
|
|
655
444
|
const createdFiles = [];
|
|
656
445
|
try {
|
|
657
|
-
const pkgPath =
|
|
658
|
-
if (!
|
|
446
|
+
const pkgPath = path2.join(cwd, "package.json");
|
|
447
|
+
if (!fs2.existsSync(pkgPath)) {
|
|
659
448
|
const pkg = {
|
|
660
449
|
name: projectName,
|
|
661
450
|
version: "0.1.0",
|
|
@@ -665,16 +454,16 @@ var initCommand = new Command4("init").description("Initialize a new ObjectStack
|
|
|
665
454
|
dependencies: template.dependencies,
|
|
666
455
|
devDependencies: template.devDependencies
|
|
667
456
|
};
|
|
668
|
-
|
|
457
|
+
fs2.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
669
458
|
createdFiles.push("package.json");
|
|
670
459
|
} else {
|
|
671
460
|
printInfo("package.json already exists, skipping");
|
|
672
461
|
}
|
|
673
462
|
const configContent = template.configContent(projectName);
|
|
674
|
-
|
|
463
|
+
fs2.writeFileSync(path2.join(cwd, "objectstack.config.ts"), configContent);
|
|
675
464
|
createdFiles.push("objectstack.config.ts");
|
|
676
|
-
const tsconfigPath =
|
|
677
|
-
if (!
|
|
465
|
+
const tsconfigPath = path2.join(cwd, "tsconfig.json");
|
|
466
|
+
if (!fs2.existsSync(tsconfigPath)) {
|
|
678
467
|
const tsconfig = {
|
|
679
468
|
compilerOptions: {
|
|
680
469
|
target: "ES2022",
|
|
@@ -690,30 +479,30 @@ var initCommand = new Command4("init").description("Initialize a new ObjectStack
|
|
|
690
479
|
include: ["*.ts", "src/**/*"],
|
|
691
480
|
exclude: ["dist", "node_modules"]
|
|
692
481
|
};
|
|
693
|
-
|
|
482
|
+
fs2.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n");
|
|
694
483
|
createdFiles.push("tsconfig.json");
|
|
695
484
|
}
|
|
696
485
|
for (const [filePath, contentFn] of Object.entries(template.srcFiles)) {
|
|
697
486
|
const resolvedPath = filePath.replace("__name__", projectName);
|
|
698
|
-
const fullPath =
|
|
699
|
-
const dir =
|
|
700
|
-
if (!
|
|
701
|
-
|
|
487
|
+
const fullPath = path2.join(cwd, resolvedPath);
|
|
488
|
+
const dir = path2.dirname(fullPath);
|
|
489
|
+
if (!fs2.existsSync(dir)) {
|
|
490
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
702
491
|
}
|
|
703
|
-
|
|
492
|
+
fs2.writeFileSync(fullPath, contentFn(projectName));
|
|
704
493
|
createdFiles.push(resolvedPath);
|
|
705
494
|
}
|
|
706
|
-
const gitignorePath =
|
|
707
|
-
if (!
|
|
708
|
-
|
|
495
|
+
const gitignorePath = path2.join(cwd, ".gitignore");
|
|
496
|
+
if (!fs2.existsSync(gitignorePath)) {
|
|
497
|
+
fs2.writeFileSync(gitignorePath, `node_modules/
|
|
709
498
|
dist/
|
|
710
499
|
*.tsbuildinfo
|
|
711
500
|
`);
|
|
712
501
|
createdFiles.push(".gitignore");
|
|
713
502
|
}
|
|
714
|
-
console.log(
|
|
503
|
+
console.log(chalk4.bold(" Created files:"));
|
|
715
504
|
for (const f of createdFiles) {
|
|
716
|
-
console.log(
|
|
505
|
+
console.log(chalk4.green(` + ${f}`));
|
|
717
506
|
}
|
|
718
507
|
console.log("");
|
|
719
508
|
if (options.install !== false) {
|
|
@@ -727,10 +516,10 @@ dist/
|
|
|
727
516
|
}
|
|
728
517
|
printSuccess("Project initialized!");
|
|
729
518
|
console.log("");
|
|
730
|
-
console.log(
|
|
731
|
-
console.log(
|
|
732
|
-
console.log(
|
|
733
|
-
console.log(
|
|
519
|
+
console.log(chalk4.bold(" Next steps:"));
|
|
520
|
+
console.log(chalk4.dim(" objectstack validate # Check configuration"));
|
|
521
|
+
console.log(chalk4.dim(" objectstack dev # Start development server"));
|
|
522
|
+
console.log(chalk4.dim(" objectstack generate # Add objects, views, etc."));
|
|
734
523
|
console.log("");
|
|
735
524
|
} catch (error) {
|
|
736
525
|
printError(error.message || String(error));
|
|
@@ -738,14 +527,14 @@ dist/
|
|
|
738
527
|
}
|
|
739
528
|
});
|
|
740
529
|
function printWarning2(msg) {
|
|
741
|
-
console.log(
|
|
530
|
+
console.log(chalk4.yellow(` \u26A0 ${msg}`));
|
|
742
531
|
}
|
|
743
532
|
|
|
744
533
|
// src/commands/generate.ts
|
|
745
534
|
import { Command as Command5 } from "commander";
|
|
746
|
-
import
|
|
747
|
-
import
|
|
748
|
-
import
|
|
535
|
+
import chalk5 from "chalk";
|
|
536
|
+
import fs3 from "fs";
|
|
537
|
+
import path3 from "path";
|
|
749
538
|
var GENERATORS = {
|
|
750
539
|
object: {
|
|
751
540
|
description: "Business data object",
|
|
@@ -926,81 +715,217 @@ function toTitleCase2(str) {
|
|
|
926
715
|
function toSnakeCase(str) {
|
|
927
716
|
return str.replace(/[-]/g, "_").replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`).replace(/^_/, "");
|
|
928
717
|
}
|
|
929
|
-
var
|
|
718
|
+
var FIELD_TYPE_MAP = {
|
|
719
|
+
text: "string",
|
|
720
|
+
textarea: "string",
|
|
721
|
+
richtext: "string",
|
|
722
|
+
html: "string",
|
|
723
|
+
markdown: "string",
|
|
724
|
+
number: "number",
|
|
725
|
+
integer: "number",
|
|
726
|
+
currency: "number",
|
|
727
|
+
percent: "number",
|
|
728
|
+
boolean: "boolean",
|
|
729
|
+
date: "string",
|
|
730
|
+
datetime: "string",
|
|
731
|
+
time: "string",
|
|
732
|
+
email: "string",
|
|
733
|
+
phone: "string",
|
|
734
|
+
url: "string",
|
|
735
|
+
select: "string",
|
|
736
|
+
multiselect: "string[]",
|
|
737
|
+
lookup: "string",
|
|
738
|
+
master_detail: "string",
|
|
739
|
+
formula: "unknown",
|
|
740
|
+
autonumber: "string",
|
|
741
|
+
json: "Record<string, unknown>",
|
|
742
|
+
file: "string",
|
|
743
|
+
image: "string",
|
|
744
|
+
password: "string",
|
|
745
|
+
slug: "string",
|
|
746
|
+
uuid: "string",
|
|
747
|
+
ip_address: "string",
|
|
748
|
+
color: "string",
|
|
749
|
+
rating: "number",
|
|
750
|
+
geo_point: "{ lat: number; lng: number }",
|
|
751
|
+
vector: "number[]",
|
|
752
|
+
encrypted: "string"
|
|
753
|
+
};
|
|
754
|
+
function fieldTypeToTs(fieldType, multiple) {
|
|
755
|
+
const base = FIELD_TYPE_MAP[fieldType] || "unknown";
|
|
756
|
+
return multiple ? `${base}[]` : base;
|
|
757
|
+
}
|
|
758
|
+
function generateTypesFromConfig(config) {
|
|
759
|
+
const lines = [
|
|
760
|
+
"// Auto-generated by ObjectStack CLI \u2014 do not edit manually",
|
|
761
|
+
`// Generated at ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
762
|
+
"",
|
|
763
|
+
"import type { Data } from '@objectstack/spec';",
|
|
764
|
+
""
|
|
765
|
+
];
|
|
766
|
+
const objects = [];
|
|
767
|
+
const rawObjects = config.objects ?? config.data?.objects ?? {};
|
|
768
|
+
if (Array.isArray(rawObjects)) {
|
|
769
|
+
objects.push(...rawObjects);
|
|
770
|
+
} else if (typeof rawObjects === "object") {
|
|
771
|
+
for (const val of Object.values(rawObjects)) {
|
|
772
|
+
if (val && typeof val === "object") objects.push(val);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
if (objects.length === 0) {
|
|
776
|
+
lines.push("// No objects found in configuration");
|
|
777
|
+
return lines.join("\n") + "\n";
|
|
778
|
+
}
|
|
779
|
+
for (const obj of objects) {
|
|
780
|
+
const name = String(obj.name || "unknown");
|
|
781
|
+
const typeName = name.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
|
|
782
|
+
const fields = obj.fields ?? {};
|
|
783
|
+
lines.push(`/** ${String(obj.label || typeName)} record type */`);
|
|
784
|
+
lines.push(`export interface ${typeName}Record {`);
|
|
785
|
+
lines.push(" id: string;");
|
|
786
|
+
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
787
|
+
const fType = String(fieldDef.type || "text");
|
|
788
|
+
const tsType = fieldTypeToTs(fType, !!fieldDef.multiple);
|
|
789
|
+
const required = fieldDef.required ? "" : "?";
|
|
790
|
+
if (fieldDef.label) {
|
|
791
|
+
lines.push(` /** ${fieldDef.label} */`);
|
|
792
|
+
}
|
|
793
|
+
lines.push(` ${fieldName}${required}: ${tsType};`);
|
|
794
|
+
}
|
|
795
|
+
lines.push("}");
|
|
796
|
+
lines.push("");
|
|
797
|
+
}
|
|
798
|
+
return lines.join("\n") + "\n";
|
|
799
|
+
}
|
|
800
|
+
var generateMetadataCommand = new Command5("metadata").alias("m").description("Generate metadata scaffold (object, view, action, flow, agent, dashboard, app)").argument("<type>", "Metadata type to generate").argument("<name>", "Name for the metadata (use kebab-case)").option("-d, --dir <directory>", "Target directory (overrides default)").option("--dry-run", "Show what would be created without writing files").action(async (type, name, options) => {
|
|
930
801
|
printHeader("Generate");
|
|
931
802
|
const generator = GENERATORS[type];
|
|
932
803
|
if (!generator) {
|
|
933
804
|
printError(`Unknown type: ${type}`);
|
|
934
805
|
console.log("");
|
|
935
|
-
console.log(
|
|
806
|
+
console.log(chalk5.bold(" Available types:"));
|
|
936
807
|
for (const [key, gen] of Object.entries(GENERATORS)) {
|
|
937
|
-
console.log(` ${
|
|
808
|
+
console.log(` ${chalk5.cyan(key.padEnd(12))} ${chalk5.dim(gen.description)}`);
|
|
938
809
|
}
|
|
939
810
|
console.log("");
|
|
940
|
-
console.log(
|
|
941
|
-
console.log(
|
|
942
|
-
console.log(
|
|
811
|
+
console.log(chalk5.dim(" Usage: objectstack generate <type> <name>"));
|
|
812
|
+
console.log(chalk5.dim(" Example: objectstack generate object project"));
|
|
813
|
+
console.log(chalk5.dim(" Alias: os g object project"));
|
|
943
814
|
process.exit(1);
|
|
944
815
|
}
|
|
945
816
|
const dir = options.dir || generator.defaultDir;
|
|
946
817
|
const fileName = `${toSnakeCase(name)}.ts`;
|
|
947
|
-
const filePath =
|
|
948
|
-
console.log(` ${
|
|
949
|
-
console.log(` ${
|
|
950
|
-
console.log(` ${
|
|
818
|
+
const filePath = path3.join(process.cwd(), dir, fileName);
|
|
819
|
+
console.log(` ${chalk5.dim("Type:")} ${chalk5.cyan(type)} \u2014 ${generator.description}`);
|
|
820
|
+
console.log(` ${chalk5.dim("Name:")} ${chalk5.white(name)}`);
|
|
821
|
+
console.log(` ${chalk5.dim("File:")} ${chalk5.white(path3.join(dir, fileName))}`);
|
|
951
822
|
console.log("");
|
|
952
823
|
if (options.dryRun) {
|
|
953
824
|
printInfo("Dry run \u2014 no files written");
|
|
954
825
|
console.log("");
|
|
955
|
-
console.log(
|
|
956
|
-
console.log(
|
|
826
|
+
console.log(chalk5.dim(" Content:"));
|
|
827
|
+
console.log(chalk5.dim(" " + "-".repeat(38)));
|
|
957
828
|
const content = generator.generate(name);
|
|
958
829
|
for (const line of content.split("\n")) {
|
|
959
|
-
console.log(
|
|
830
|
+
console.log(chalk5.dim(` ${line}`));
|
|
960
831
|
}
|
|
961
832
|
console.log("");
|
|
962
833
|
return;
|
|
963
834
|
}
|
|
964
|
-
if (
|
|
835
|
+
if (fs3.existsSync(filePath)) {
|
|
965
836
|
printError(`File already exists: ${filePath}`);
|
|
966
837
|
process.exit(1);
|
|
967
838
|
}
|
|
968
839
|
try {
|
|
969
|
-
const fullDir =
|
|
970
|
-
if (!
|
|
971
|
-
|
|
840
|
+
const fullDir = path3.dirname(filePath);
|
|
841
|
+
if (!fs3.existsSync(fullDir)) {
|
|
842
|
+
fs3.mkdirSync(fullDir, { recursive: true });
|
|
972
843
|
}
|
|
973
844
|
const content = generator.generate(name);
|
|
974
|
-
|
|
975
|
-
printSuccess(`Created ${
|
|
976
|
-
const indexPath =
|
|
977
|
-
if (
|
|
978
|
-
const indexContent =
|
|
845
|
+
fs3.writeFileSync(filePath, content);
|
|
846
|
+
printSuccess(`Created ${path3.join(dir, fileName)}`);
|
|
847
|
+
const indexPath = path3.join(process.cwd(), dir, "index.ts");
|
|
848
|
+
if (fs3.existsSync(indexPath)) {
|
|
849
|
+
const indexContent = fs3.readFileSync(indexPath, "utf-8");
|
|
979
850
|
const exportLine = `export { default as ${toCamelCase2(name)} } from './${toSnakeCase(name)}';`;
|
|
980
851
|
if (!indexContent.includes(toCamelCase2(name))) {
|
|
981
|
-
|
|
852
|
+
fs3.appendFileSync(indexPath, exportLine + "\n");
|
|
982
853
|
printSuccess(`Updated ${dir}/index.ts with export`);
|
|
983
854
|
}
|
|
984
855
|
} else {
|
|
985
856
|
const exportLine = `export { default as ${toCamelCase2(name)} } from './${toSnakeCase(name)}';
|
|
986
857
|
`;
|
|
987
|
-
|
|
858
|
+
fs3.writeFileSync(indexPath, exportLine);
|
|
988
859
|
printSuccess(`Created ${dir}/index.ts`);
|
|
989
860
|
}
|
|
990
861
|
console.log("");
|
|
991
|
-
console.log(
|
|
862
|
+
console.log(chalk5.dim(` Tip: Run \`objectstack validate\` to check your config`));
|
|
992
863
|
console.log("");
|
|
993
864
|
} catch (error) {
|
|
994
865
|
printError(error.message || String(error));
|
|
995
866
|
process.exit(1);
|
|
996
867
|
}
|
|
997
868
|
});
|
|
869
|
+
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) => {
|
|
870
|
+
printHeader("Generate Types");
|
|
871
|
+
try {
|
|
872
|
+
const { loadConfig: loadConfig2 } = await import("./config-UN34WBHT.js");
|
|
873
|
+
printInfo("Loading configuration...");
|
|
874
|
+
const { config, absolutePath } = await loadConfig2(configPath);
|
|
875
|
+
console.log(` ${chalk5.dim("Config:")} ${chalk5.white(absolutePath)}`);
|
|
876
|
+
console.log(` ${chalk5.dim("Output:")} ${chalk5.white(options.output)}`);
|
|
877
|
+
console.log("");
|
|
878
|
+
const content = generateTypesFromConfig(config);
|
|
879
|
+
if (options.dryRun) {
|
|
880
|
+
printInfo("Dry run \u2014 no files written");
|
|
881
|
+
console.log("");
|
|
882
|
+
for (const line of content.split("\n")) {
|
|
883
|
+
console.log(chalk5.dim(` ${line}`));
|
|
884
|
+
}
|
|
885
|
+
console.log("");
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
const outPath = path3.resolve(process.cwd(), options.output);
|
|
889
|
+
const outDir = path3.dirname(outPath);
|
|
890
|
+
if (!fs3.existsSync(outDir)) {
|
|
891
|
+
fs3.mkdirSync(outDir, { recursive: true });
|
|
892
|
+
}
|
|
893
|
+
fs3.writeFileSync(outPath, content);
|
|
894
|
+
printSuccess(`Generated types at ${options.output}`);
|
|
895
|
+
console.log("");
|
|
896
|
+
} catch (error) {
|
|
897
|
+
printError(error.message || String(error));
|
|
898
|
+
process.exit(1);
|
|
899
|
+
}
|
|
900
|
+
});
|
|
901
|
+
var generateCommand = new Command5("generate").alias("g").description("Generate metadata files or TypeScript types").argument("[type]", "Metadata type to generate (object, view, action, flow, agent, dashboard, app)").argument("[name]", "Name for the metadata (use kebab-case)").option("-d, --dir <directory>", "Target directory (overrides default)").option("--dry-run", "Show what would be created without writing files").addCommand(generateTypesCommand).action(async (type, name, options) => {
|
|
902
|
+
if (!type) {
|
|
903
|
+
printHeader("Generate");
|
|
904
|
+
console.log(chalk5.bold(" Sub-commands:"));
|
|
905
|
+
console.log(` ${chalk5.cyan("types".padEnd(12))} Generate TypeScript type definitions from config`);
|
|
906
|
+
console.log("");
|
|
907
|
+
console.log(chalk5.bold(" Metadata types:"));
|
|
908
|
+
for (const [key, gen] of Object.entries(GENERATORS)) {
|
|
909
|
+
console.log(` ${chalk5.cyan(key.padEnd(12))} ${chalk5.dim(gen.description)}`);
|
|
910
|
+
}
|
|
911
|
+
console.log("");
|
|
912
|
+
console.log(chalk5.dim(" Usage: objectstack generate <type> <name>"));
|
|
913
|
+
console.log(chalk5.dim(" Usage: objectstack generate types [config]"));
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
if (!name) {
|
|
917
|
+
printError("Missing required argument: <name>");
|
|
918
|
+
console.log(chalk5.dim(" Usage: objectstack generate <type> <name>"));
|
|
919
|
+
process.exit(1);
|
|
920
|
+
}
|
|
921
|
+
await generateMetadataCommand.parseAsync([type, name, ...process.argv.slice(4)], { from: "user" });
|
|
922
|
+
});
|
|
998
923
|
|
|
999
924
|
// src/commands/create.ts
|
|
1000
925
|
import { Command as Command6 } from "commander";
|
|
1001
|
-
import
|
|
1002
|
-
import
|
|
1003
|
-
import
|
|
926
|
+
import chalk6 from "chalk";
|
|
927
|
+
import fs4 from "fs";
|
|
928
|
+
import path4 from "path";
|
|
1004
929
|
var templates = {
|
|
1005
930
|
plugin: {
|
|
1006
931
|
description: "Create a new ObjectStack plugin",
|
|
@@ -1175,64 +1100,64 @@ function toCamelCase3(str) {
|
|
|
1175
1100
|
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
1176
1101
|
}
|
|
1177
1102
|
var createCommand = new Command6("create").description("Create a new package, plugin, or example from template").argument("<type>", "Type of project to create (plugin, example)").argument("[name]", "Name of the project").option("-d, --dir <directory>", "Target directory").action(async (type, name, options) => {
|
|
1178
|
-
console.log(
|
|
1103
|
+
console.log(chalk6.bold(`
|
|
1179
1104
|
\u{1F4E6} ObjectStack Project Creator`));
|
|
1180
|
-
console.log(
|
|
1105
|
+
console.log(chalk6.dim(`-------------------------------`));
|
|
1181
1106
|
if (!templates[type]) {
|
|
1182
|
-
console.error(
|
|
1107
|
+
console.error(chalk6.red(`
|
|
1183
1108
|
\u274C Unknown type: ${type}`));
|
|
1184
|
-
console.log(
|
|
1109
|
+
console.log(chalk6.dim("Available types: plugin, example"));
|
|
1185
1110
|
process.exit(1);
|
|
1186
1111
|
}
|
|
1187
1112
|
if (!name) {
|
|
1188
|
-
console.error(
|
|
1189
|
-
console.log(
|
|
1113
|
+
console.error(chalk6.red("\n\u274C Project name is required"));
|
|
1114
|
+
console.log(chalk6.dim(`Usage: objectstack create ${type} <name>`));
|
|
1190
1115
|
process.exit(1);
|
|
1191
1116
|
}
|
|
1192
1117
|
const template = templates[type];
|
|
1193
1118
|
const cwd = process.cwd();
|
|
1194
1119
|
let targetDir;
|
|
1195
1120
|
if (options?.dir) {
|
|
1196
|
-
targetDir =
|
|
1121
|
+
targetDir = path4.resolve(cwd, options.dir);
|
|
1197
1122
|
} else {
|
|
1198
1123
|
const baseDir = type === "plugin" ? "packages/plugins" : "examples";
|
|
1199
1124
|
const projectName = type === "plugin" ? `plugin-${name}` : name;
|
|
1200
|
-
targetDir =
|
|
1125
|
+
targetDir = path4.join(cwd, baseDir, projectName);
|
|
1201
1126
|
}
|
|
1202
|
-
if (
|
|
1203
|
-
console.error(
|
|
1127
|
+
if (fs4.existsSync(targetDir)) {
|
|
1128
|
+
console.error(chalk6.red(`
|
|
1204
1129
|
\u274C Directory already exists: ${targetDir}`));
|
|
1205
1130
|
process.exit(1);
|
|
1206
1131
|
}
|
|
1207
|
-
console.log(`\u{1F4C1} Creating ${type}: ${
|
|
1208
|
-
console.log(`\u{1F4C2} Location: ${
|
|
1132
|
+
console.log(`\u{1F4C1} Creating ${type}: ${chalk6.blue(name)}`);
|
|
1133
|
+
console.log(`\u{1F4C2} Location: ${chalk6.dim(targetDir)}`);
|
|
1209
1134
|
console.log("");
|
|
1210
1135
|
try {
|
|
1211
|
-
|
|
1136
|
+
fs4.mkdirSync(targetDir, { recursive: true });
|
|
1212
1137
|
for (const [filePath, contentFn] of Object.entries(template.files)) {
|
|
1213
|
-
const fullPath =
|
|
1214
|
-
const dir =
|
|
1215
|
-
if (!
|
|
1216
|
-
|
|
1138
|
+
const fullPath = path4.join(targetDir, filePath);
|
|
1139
|
+
const dir = path4.dirname(fullPath);
|
|
1140
|
+
if (!fs4.existsSync(dir)) {
|
|
1141
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
1217
1142
|
}
|
|
1218
1143
|
const content = contentFn(name);
|
|
1219
1144
|
const fileContent = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
1220
|
-
|
|
1221
|
-
console.log(
|
|
1145
|
+
fs4.writeFileSync(fullPath, fileContent);
|
|
1146
|
+
console.log(chalk6.green(`\u2713 Created ${filePath}`));
|
|
1222
1147
|
}
|
|
1223
1148
|
console.log("");
|
|
1224
|
-
console.log(
|
|
1149
|
+
console.log(chalk6.green("\u2705 Project created successfully!"));
|
|
1225
1150
|
console.log("");
|
|
1226
|
-
console.log(
|
|
1227
|
-
console.log(
|
|
1228
|
-
console.log(
|
|
1229
|
-
console.log(
|
|
1151
|
+
console.log(chalk6.bold("Next steps:"));
|
|
1152
|
+
console.log(chalk6.dim(` cd ${path4.relative(cwd, targetDir)}`));
|
|
1153
|
+
console.log(chalk6.dim(" pnpm install"));
|
|
1154
|
+
console.log(chalk6.dim(" pnpm build"));
|
|
1230
1155
|
console.log("");
|
|
1231
1156
|
} catch (error) {
|
|
1232
|
-
console.error(
|
|
1157
|
+
console.error(chalk6.red("\n\u274C Failed to create project:"));
|
|
1233
1158
|
console.error(error.message || error);
|
|
1234
|
-
if (
|
|
1235
|
-
|
|
1159
|
+
if (fs4.existsSync(targetDir)) {
|
|
1160
|
+
fs4.rmSync(targetDir, { recursive: true });
|
|
1236
1161
|
}
|
|
1237
1162
|
process.exit(1);
|
|
1238
1163
|
}
|
|
@@ -1240,9 +1165,9 @@ var createCommand = new Command6("create").description("Create a new package, pl
|
|
|
1240
1165
|
|
|
1241
1166
|
// src/commands/plugin.ts
|
|
1242
1167
|
import { Command as Command7 } from "commander";
|
|
1243
|
-
import
|
|
1244
|
-
import
|
|
1245
|
-
import
|
|
1168
|
+
import chalk7 from "chalk";
|
|
1169
|
+
import fs5 from "fs";
|
|
1170
|
+
import path5 from "path";
|
|
1246
1171
|
function resolvePluginName(plugin) {
|
|
1247
1172
|
if (typeof plugin === "string") return plugin;
|
|
1248
1173
|
if (plugin && typeof plugin === "object") {
|
|
@@ -1267,7 +1192,7 @@ function resolvePluginType(plugin) {
|
|
|
1267
1192
|
return "standard";
|
|
1268
1193
|
}
|
|
1269
1194
|
function readConfigText(configPath) {
|
|
1270
|
-
return
|
|
1195
|
+
return fs5.readFileSync(configPath, "utf-8");
|
|
1271
1196
|
}
|
|
1272
1197
|
function addPluginToConfig(configPath, packageName) {
|
|
1273
1198
|
let content = readConfigText(configPath);
|
|
@@ -1309,7 +1234,7 @@ function addPluginToConfig(configPath, packageName) {
|
|
|
1309
1234
|
$2`
|
|
1310
1235
|
);
|
|
1311
1236
|
}
|
|
1312
|
-
|
|
1237
|
+
fs5.writeFileSync(configPath, content);
|
|
1313
1238
|
}
|
|
1314
1239
|
function removePluginFromConfig(configPath, pluginName) {
|
|
1315
1240
|
let content = readConfigText(configPath);
|
|
@@ -1331,7 +1256,7 @@ function removePluginFromConfig(configPath, pluginName) {
|
|
|
1331
1256
|
content = content.replace(pattern, "\n");
|
|
1332
1257
|
}
|
|
1333
1258
|
content = content.replace(/plugins\s*:\s*\[\s*\],?\n?/g, "");
|
|
1334
|
-
|
|
1259
|
+
fs5.writeFileSync(configPath, content);
|
|
1335
1260
|
}
|
|
1336
1261
|
function escapeRegex(str) {
|
|
1337
1262
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -1363,31 +1288,31 @@ var listCommand = new Command7("list").alias("ls").description("List plugins def
|
|
|
1363
1288
|
if (plugins.length === 0 && devPlugins.length === 0) {
|
|
1364
1289
|
printInfo("No plugins configured");
|
|
1365
1290
|
console.log("");
|
|
1366
|
-
console.log(
|
|
1367
|
-
console.log(
|
|
1291
|
+
console.log(chalk7.dim(" Hint: Add plugins to your objectstack.config.ts"));
|
|
1292
|
+
console.log(chalk7.dim(" Or run: os plugin add <package-name>"));
|
|
1368
1293
|
console.log("");
|
|
1369
1294
|
return;
|
|
1370
1295
|
}
|
|
1371
1296
|
if (plugins.length > 0) {
|
|
1372
|
-
console.log(
|
|
1297
|
+
console.log(chalk7.bold(`
|
|
1373
1298
|
Plugins (${plugins.length}):`));
|
|
1374
1299
|
for (const plugin of plugins) {
|
|
1375
1300
|
const name = resolvePluginName(plugin);
|
|
1376
1301
|
const version = resolvePluginVersion(plugin);
|
|
1377
1302
|
const type = resolvePluginType(plugin);
|
|
1378
1303
|
console.log(
|
|
1379
|
-
` ${
|
|
1304
|
+
` ${chalk7.cyan("\u25CF")} ${chalk7.white(name)}` + (version !== "-" ? chalk7.dim(` v${version}`) : "") + (type !== "standard" ? chalk7.dim(` [${type}]`) : "")
|
|
1380
1305
|
);
|
|
1381
1306
|
}
|
|
1382
1307
|
}
|
|
1383
1308
|
if (devPlugins.length > 0) {
|
|
1384
|
-
console.log(
|
|
1309
|
+
console.log(chalk7.bold(`
|
|
1385
1310
|
Dev Plugins (${devPlugins.length}):`));
|
|
1386
1311
|
for (const plugin of devPlugins) {
|
|
1387
1312
|
const name = resolvePluginName(plugin);
|
|
1388
1313
|
const version = resolvePluginVersion(plugin);
|
|
1389
1314
|
console.log(
|
|
1390
|
-
` ${
|
|
1315
|
+
` ${chalk7.yellow("\u25CF")} ${chalk7.white(name)}` + (version !== "-" ? chalk7.dim(` v${version}`) : "") + chalk7.dim(" [dev]")
|
|
1391
1316
|
);
|
|
1392
1317
|
}
|
|
1393
1318
|
}
|
|
@@ -1411,9 +1336,9 @@ var infoSubCommand = new Command7("info").description("Show detailed information
|
|
|
1411
1336
|
if (!found) {
|
|
1412
1337
|
printError(`Plugin '${name}' not found in configuration`);
|
|
1413
1338
|
console.log("");
|
|
1414
|
-
console.log(
|
|
1339
|
+
console.log(chalk7.dim(" Available plugins:"));
|
|
1415
1340
|
for (const p of allPlugins) {
|
|
1416
|
-
console.log(
|
|
1341
|
+
console.log(chalk7.dim(` - ${resolvePluginName(p)}`));
|
|
1417
1342
|
}
|
|
1418
1343
|
console.log("");
|
|
1419
1344
|
process.exit(1);
|
|
@@ -1449,15 +1374,15 @@ var addCommand = new Command7("add").description("Add a plugin to objectstack.co
|
|
|
1449
1374
|
try {
|
|
1450
1375
|
const configPath = resolveConfigPath(options?.config);
|
|
1451
1376
|
printHeader("Add Plugin");
|
|
1452
|
-
console.log(` ${
|
|
1453
|
-
console.log(` ${
|
|
1377
|
+
console.log(` ${chalk7.dim("Package:")} ${chalk7.white(packageName)}`);
|
|
1378
|
+
console.log(` ${chalk7.dim("Config:")} ${chalk7.white(path5.relative(process.cwd(), configPath))}`);
|
|
1454
1379
|
console.log("");
|
|
1455
1380
|
addPluginToConfig(configPath, packageName);
|
|
1456
|
-
printSuccess(`Added ${
|
|
1381
|
+
printSuccess(`Added ${chalk7.cyan(packageName)} to config`);
|
|
1457
1382
|
console.log("");
|
|
1458
|
-
console.log(
|
|
1459
|
-
console.log(
|
|
1460
|
-
console.log(
|
|
1383
|
+
console.log(chalk7.dim(" Next steps:"));
|
|
1384
|
+
console.log(chalk7.dim(` 1. Install the package: pnpm add ${packageName}`));
|
|
1385
|
+
console.log(chalk7.dim(" 2. Run: os validate"));
|
|
1461
1386
|
console.log("");
|
|
1462
1387
|
} catch (error) {
|
|
1463
1388
|
printError(error.message || String(error));
|
|
@@ -1468,13 +1393,13 @@ var removeCommand = new Command7("remove").alias("rm").description("Remove a plu
|
|
|
1468
1393
|
try {
|
|
1469
1394
|
const configPath = resolveConfigPath(options?.config);
|
|
1470
1395
|
printHeader("Remove Plugin");
|
|
1471
|
-
console.log(` ${
|
|
1472
|
-
console.log(` ${
|
|
1396
|
+
console.log(` ${chalk7.dim("Plugin:")} ${chalk7.white(pluginName)}`);
|
|
1397
|
+
console.log(` ${chalk7.dim("Config:")} ${chalk7.white(path5.relative(process.cwd(), configPath))}`);
|
|
1473
1398
|
console.log("");
|
|
1474
1399
|
removePluginFromConfig(configPath, pluginName);
|
|
1475
|
-
printSuccess(`Removed ${
|
|
1400
|
+
printSuccess(`Removed ${chalk7.cyan(pluginName)} from config`);
|
|
1476
1401
|
console.log("");
|
|
1477
|
-
console.log(
|
|
1402
|
+
console.log(chalk7.dim(" Tip: Run `pnpm remove " + pluginName + "` to uninstall the package"));
|
|
1478
1403
|
console.log("");
|
|
1479
1404
|
} catch (error) {
|
|
1480
1405
|
printError(error.message || String(error));
|
|
@@ -1485,14 +1410,14 @@ var pluginCommand = new Command7("plugin").description("Manage plugins (list, in
|
|
|
1485
1410
|
|
|
1486
1411
|
// src/commands/dev.ts
|
|
1487
1412
|
import { Command as Command8 } from "commander";
|
|
1488
|
-
import
|
|
1413
|
+
import chalk8 from "chalk";
|
|
1489
1414
|
import { execSync, spawn } from "child_process";
|
|
1490
|
-
import
|
|
1491
|
-
import
|
|
1415
|
+
import fs6 from "fs";
|
|
1416
|
+
import path6 from "path";
|
|
1492
1417
|
var devCommand = new Command8("dev").description("Start development mode with hot-reload").argument("[package]", "Package name or filter pattern", "all").option("-w, --watch", "Enable watch mode (default)", true).option("--ui", "Enable Studio UI at /_studio/").option("-v, --verbose", "Verbose output").action(async (packageName, options) => {
|
|
1493
1418
|
printHeader("Development Mode");
|
|
1494
|
-
const configPath =
|
|
1495
|
-
if (packageName === "all" &&
|
|
1419
|
+
const configPath = path6.resolve(process.cwd(), "objectstack.config.ts");
|
|
1420
|
+
if (packageName === "all" && fs6.existsSync(configPath)) {
|
|
1496
1421
|
printKV("Config", configPath, "\u{1F4C2}");
|
|
1497
1422
|
printStep("Starting dev server...");
|
|
1498
1423
|
const binPath = process.argv[1];
|
|
@@ -1504,18 +1429,18 @@ var devCommand = new Command8("dev").description("Start development mode with ho
|
|
|
1504
1429
|
}
|
|
1505
1430
|
try {
|
|
1506
1431
|
const cwd = process.cwd();
|
|
1507
|
-
const workspaceConfigPath =
|
|
1508
|
-
const isWorkspaceRoot =
|
|
1432
|
+
const workspaceConfigPath = path6.resolve(cwd, "pnpm-workspace.yaml");
|
|
1433
|
+
const isWorkspaceRoot = fs6.existsSync(workspaceConfigPath);
|
|
1509
1434
|
if (packageName === "all" && !isWorkspaceRoot) {
|
|
1510
1435
|
printError(`Config file not found in ${cwd}`);
|
|
1511
|
-
console.error(
|
|
1436
|
+
console.error(chalk8.yellow(" Run in a directory with objectstack.config.ts, or from the monorepo root."));
|
|
1512
1437
|
process.exit(1);
|
|
1513
1438
|
}
|
|
1514
1439
|
const filter = packageName === "all" ? "" : `--filter ${packageName}`;
|
|
1515
1440
|
printKV("Package", packageName === "all" ? "All packages" : packageName, "\u{1F4E6}");
|
|
1516
1441
|
printKV("Watch", "enabled", "\u{1F504}");
|
|
1517
1442
|
const command = `pnpm ${filter} dev`.trim();
|
|
1518
|
-
console.log(
|
|
1443
|
+
console.log(chalk8.dim(`$ ${command}`));
|
|
1519
1444
|
console.log("");
|
|
1520
1445
|
execSync(command, {
|
|
1521
1446
|
stdio: "inherit",
|
|
@@ -1529,37 +1454,37 @@ var devCommand = new Command8("dev").description("Start development mode with ho
|
|
|
1529
1454
|
|
|
1530
1455
|
// src/commands/serve.ts
|
|
1531
1456
|
import { Command as Command9 } from "commander";
|
|
1532
|
-
import
|
|
1533
|
-
import
|
|
1457
|
+
import path8 from "path";
|
|
1458
|
+
import fs8 from "fs";
|
|
1534
1459
|
import net from "net";
|
|
1535
|
-
import
|
|
1536
|
-
import { bundleRequire
|
|
1460
|
+
import chalk9 from "chalk";
|
|
1461
|
+
import { bundleRequire } from "bundle-require";
|
|
1537
1462
|
|
|
1538
1463
|
// src/utils/studio.ts
|
|
1539
|
-
import
|
|
1540
|
-
import
|
|
1464
|
+
import path7 from "path";
|
|
1465
|
+
import fs7 from "fs";
|
|
1541
1466
|
import { createRequire } from "module";
|
|
1542
1467
|
import { pathToFileURL } from "url";
|
|
1543
1468
|
var STUDIO_PATH = "/_studio";
|
|
1544
1469
|
function resolveStudioPath() {
|
|
1545
1470
|
const cwd = process.cwd();
|
|
1546
1471
|
const candidates = [
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1472
|
+
path7.resolve(cwd, "apps/studio"),
|
|
1473
|
+
path7.resolve(cwd, "../../apps/studio"),
|
|
1474
|
+
path7.resolve(cwd, "../apps/studio")
|
|
1550
1475
|
];
|
|
1551
1476
|
for (const candidate of candidates) {
|
|
1552
|
-
const pkgPath =
|
|
1553
|
-
if (
|
|
1477
|
+
const pkgPath = path7.join(candidate, "package.json");
|
|
1478
|
+
if (fs7.existsSync(pkgPath)) {
|
|
1554
1479
|
try {
|
|
1555
|
-
const pkg = JSON.parse(
|
|
1480
|
+
const pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
|
|
1556
1481
|
if (pkg.name === "@objectstack/studio") return candidate;
|
|
1557
1482
|
} catch {
|
|
1558
1483
|
}
|
|
1559
1484
|
}
|
|
1560
1485
|
}
|
|
1561
1486
|
const resolutionBases = [
|
|
1562
|
-
pathToFileURL(
|
|
1487
|
+
pathToFileURL(path7.join(cwd, "package.json")).href,
|
|
1563
1488
|
// consumer workspace
|
|
1564
1489
|
import.meta.url
|
|
1565
1490
|
// CLI package itself
|
|
@@ -1568,18 +1493,18 @@ function resolveStudioPath() {
|
|
|
1568
1493
|
try {
|
|
1569
1494
|
const req = createRequire(base);
|
|
1570
1495
|
const resolved = req.resolve("@objectstack/studio/package.json");
|
|
1571
|
-
return
|
|
1496
|
+
return path7.dirname(resolved);
|
|
1572
1497
|
} catch {
|
|
1573
1498
|
}
|
|
1574
1499
|
}
|
|
1575
|
-
const directPath =
|
|
1576
|
-
if (
|
|
1500
|
+
const directPath = path7.join(cwd, "node_modules", "@objectstack", "studio");
|
|
1501
|
+
if (fs7.existsSync(path7.join(directPath, "package.json"))) {
|
|
1577
1502
|
return directPath;
|
|
1578
1503
|
}
|
|
1579
1504
|
return null;
|
|
1580
1505
|
}
|
|
1581
1506
|
function hasStudioDist(studioPath) {
|
|
1582
|
-
return
|
|
1507
|
+
return fs7.existsSync(path7.join(studioPath, "dist", "index.html"));
|
|
1583
1508
|
}
|
|
1584
1509
|
function createStudioStaticPlugin(distPath, options) {
|
|
1585
1510
|
return {
|
|
@@ -1593,13 +1518,13 @@ function createStudioStaticPlugin(distPath, options) {
|
|
|
1593
1518
|
return;
|
|
1594
1519
|
}
|
|
1595
1520
|
const app = httpServer.getRawApp();
|
|
1596
|
-
const absoluteDist =
|
|
1597
|
-
const indexPath =
|
|
1598
|
-
if (!
|
|
1521
|
+
const absoluteDist = path7.resolve(distPath);
|
|
1522
|
+
const indexPath = path7.join(absoluteDist, "index.html");
|
|
1523
|
+
if (!fs7.existsSync(indexPath)) {
|
|
1599
1524
|
ctx.logger?.warn?.(`Studio static: dist not found at ${absoluteDist}`);
|
|
1600
1525
|
return;
|
|
1601
1526
|
}
|
|
1602
|
-
const rawHtml =
|
|
1527
|
+
const rawHtml = fs7.readFileSync(indexPath, "utf-8");
|
|
1603
1528
|
const rewrittenHtml = rawHtml.replace(
|
|
1604
1529
|
/(\s(?:href|src))="\/(?!\/)/g,
|
|
1605
1530
|
`$1="${STUDIO_PATH}/`
|
|
@@ -1610,12 +1535,12 @@ function createStudioStaticPlugin(distPath, options) {
|
|
|
1610
1535
|
app.get(STUDIO_PATH, (c) => c.redirect(`${STUDIO_PATH}/`));
|
|
1611
1536
|
app.get(`${STUDIO_PATH}/*`, async (c) => {
|
|
1612
1537
|
const reqPath = c.req.path.substring(STUDIO_PATH.length) || "/";
|
|
1613
|
-
const filePath =
|
|
1538
|
+
const filePath = path7.join(absoluteDist, reqPath);
|
|
1614
1539
|
if (!filePath.startsWith(absoluteDist)) {
|
|
1615
1540
|
return c.text("Forbidden", 403);
|
|
1616
1541
|
}
|
|
1617
|
-
if (
|
|
1618
|
-
const content =
|
|
1542
|
+
if (fs7.existsSync(filePath) && fs7.statSync(filePath).isFile()) {
|
|
1543
|
+
const content = fs7.readFileSync(filePath);
|
|
1619
1544
|
return new Response(content, {
|
|
1620
1545
|
headers: { "content-type": mimeType(filePath) }
|
|
1621
1546
|
});
|
|
@@ -1645,7 +1570,7 @@ var MIME_TYPES = {
|
|
|
1645
1570
|
".map": "application/json"
|
|
1646
1571
|
};
|
|
1647
1572
|
function mimeType(filePath) {
|
|
1648
|
-
const ext =
|
|
1573
|
+
const ext = path7.extname(filePath).toLowerCase();
|
|
1649
1574
|
return MIME_TYPES[ext] || "application/octet-stream";
|
|
1650
1575
|
}
|
|
1651
1576
|
|
|
@@ -1682,15 +1607,15 @@ var serveCommand = new Command9("serve").description("Start ObjectStack server w
|
|
|
1682
1607
|
} catch (e) {
|
|
1683
1608
|
}
|
|
1684
1609
|
const isDev = options.dev || process.env.NODE_ENV === "development";
|
|
1685
|
-
const absolutePath =
|
|
1686
|
-
const relativeConfig =
|
|
1687
|
-
if (!
|
|
1610
|
+
const absolutePath = path8.resolve(process.cwd(), configPath);
|
|
1611
|
+
const relativeConfig = path8.relative(process.cwd(), absolutePath);
|
|
1612
|
+
if (!fs8.existsSync(absolutePath)) {
|
|
1688
1613
|
printError(`Configuration file not found: ${absolutePath}`);
|
|
1689
|
-
console.log(
|
|
1614
|
+
console.log(chalk9.dim(" Hint: Run `objectstack init` to create a new project"));
|
|
1690
1615
|
process.exit(1);
|
|
1691
1616
|
}
|
|
1692
1617
|
console.log("");
|
|
1693
|
-
console.log(
|
|
1618
|
+
console.log(chalk9.dim(` Loading ${relativeConfig}...`));
|
|
1694
1619
|
const loadedPlugins = [];
|
|
1695
1620
|
const shortPluginName = (raw) => {
|
|
1696
1621
|
if (raw.includes("objectql")) return "ObjectQL";
|
|
@@ -1725,7 +1650,7 @@ var serveCommand = new Command9("serve").description("Start ObjectStack server w
|
|
|
1725
1650
|
console.debug = (...args) => {
|
|
1726
1651
|
if (!bootQuiet) originalConsoleDebug(...args);
|
|
1727
1652
|
};
|
|
1728
|
-
const { mod } = await
|
|
1653
|
+
const { mod } = await bundleRequire({
|
|
1729
1654
|
filepath: absolutePath
|
|
1730
1655
|
});
|
|
1731
1656
|
const config = mod.default || mod;
|
|
@@ -1794,7 +1719,7 @@ var serveCommand = new Command9("serve").description("Start ObjectStack server w
|
|
|
1794
1719
|
const pluginName = plugin.name || plugin.constructor?.name || "unnamed";
|
|
1795
1720
|
trackPlugin(pluginName);
|
|
1796
1721
|
} catch (e) {
|
|
1797
|
-
console.error(
|
|
1722
|
+
console.error(chalk9.red(` \u2717 Failed to load plugin: ${e.message}`));
|
|
1798
1723
|
}
|
|
1799
1724
|
}
|
|
1800
1725
|
}
|
|
@@ -1805,7 +1730,7 @@ var serveCommand = new Command9("serve").description("Start ObjectStack server w
|
|
|
1805
1730
|
await kernel.use(serverPlugin);
|
|
1806
1731
|
trackPlugin("HonoServer");
|
|
1807
1732
|
} catch (e) {
|
|
1808
|
-
console.warn(
|
|
1733
|
+
console.warn(chalk9.yellow(` \u26A0 HTTP server plugin not available: ${e.message}`));
|
|
1809
1734
|
}
|
|
1810
1735
|
try {
|
|
1811
1736
|
const { createRestApiPlugin } = await import("@objectstack/rest");
|
|
@@ -1824,13 +1749,13 @@ var serveCommand = new Command9("serve").description("Start ObjectStack server w
|
|
|
1824
1749
|
if (enableUI) {
|
|
1825
1750
|
const studioPath = resolveStudioPath();
|
|
1826
1751
|
if (!studioPath) {
|
|
1827
|
-
console.warn(
|
|
1752
|
+
console.warn(chalk9.yellow(` \u26A0 @objectstack/studio not found \u2014 skipping UI`));
|
|
1828
1753
|
} else if (hasStudioDist(studioPath)) {
|
|
1829
|
-
const distPath =
|
|
1754
|
+
const distPath = path8.join(studioPath, "dist");
|
|
1830
1755
|
await kernel.use(createStudioStaticPlugin(distPath, { isDev }));
|
|
1831
1756
|
trackPlugin("StudioUI");
|
|
1832
1757
|
} else {
|
|
1833
|
-
console.warn(
|
|
1758
|
+
console.warn(chalk9.yellow(` \u26A0 Studio dist not found \u2014 run "pnpm --filter @objectstack/studio build" first`));
|
|
1834
1759
|
}
|
|
1835
1760
|
}
|
|
1836
1761
|
await runtime.start();
|
|
@@ -1846,33 +1771,33 @@ var serveCommand = new Command9("serve").description("Start ObjectStack server w
|
|
|
1846
1771
|
studioPath: STUDIO_PATH
|
|
1847
1772
|
});
|
|
1848
1773
|
process.on("SIGINT", async () => {
|
|
1849
|
-
console.warn(
|
|
1774
|
+
console.warn(chalk9.yellow(`
|
|
1850
1775
|
|
|
1851
1776
|
\u23F9 Stopping server...`));
|
|
1852
1777
|
await runtime.getKernel().shutdown();
|
|
1853
|
-
console.log(
|
|
1778
|
+
console.log(chalk9.green(`\u2705 Server stopped`));
|
|
1854
1779
|
process.exit(0);
|
|
1855
1780
|
});
|
|
1856
1781
|
} catch (error) {
|
|
1857
1782
|
restoreOutput();
|
|
1858
1783
|
console.log("");
|
|
1859
1784
|
printError(error.message || String(error));
|
|
1860
|
-
if (process.env.DEBUG) console.error(
|
|
1785
|
+
if (process.env.DEBUG) console.error(chalk9.dim(error.stack));
|
|
1861
1786
|
process.exit(1);
|
|
1862
1787
|
}
|
|
1863
1788
|
});
|
|
1864
1789
|
|
|
1865
1790
|
// src/commands/test.ts
|
|
1866
1791
|
import { Command as Command10 } from "commander";
|
|
1867
|
-
import
|
|
1868
|
-
import
|
|
1869
|
-
import
|
|
1792
|
+
import chalk10 from "chalk";
|
|
1793
|
+
import path9 from "path";
|
|
1794
|
+
import fs9 from "fs";
|
|
1870
1795
|
import { QA as CoreQA } from "@objectstack/core";
|
|
1871
1796
|
function resolveGlob(pattern) {
|
|
1872
1797
|
if (!pattern.includes("*")) {
|
|
1873
|
-
return
|
|
1798
|
+
return fs9.existsSync(pattern) ? [pattern] : [];
|
|
1874
1799
|
}
|
|
1875
|
-
const parts = pattern.split(
|
|
1800
|
+
const parts = pattern.split(path9.sep.replace("\\", "/"));
|
|
1876
1801
|
const segments = pattern.includes("/") ? pattern.split("/") : parts;
|
|
1877
1802
|
let baseDir = ".";
|
|
1878
1803
|
let globStart = 0;
|
|
@@ -1881,25 +1806,25 @@ function resolveGlob(pattern) {
|
|
|
1881
1806
|
globStart = i;
|
|
1882
1807
|
break;
|
|
1883
1808
|
}
|
|
1884
|
-
baseDir = i === 0 ? segments[i] :
|
|
1809
|
+
baseDir = i === 0 ? segments[i] : path9.join(baseDir, segments[i]);
|
|
1885
1810
|
}
|
|
1886
|
-
if (!
|
|
1811
|
+
if (!fs9.existsSync(baseDir)) return [];
|
|
1887
1812
|
const globPortion = segments.slice(globStart).join("/");
|
|
1888
1813
|
const regexStr = globPortion.replace(/\./g, "\\.").replace(/\*\*\//g, "(.+/)?").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
|
|
1889
1814
|
const regex = new RegExp(`^${regexStr}$`);
|
|
1890
|
-
const entries =
|
|
1891
|
-
return entries.filter((entry) => regex.test(entry.replace(/\\/g, "/"))).map((entry) =>
|
|
1815
|
+
const entries = fs9.readdirSync(baseDir, { recursive: true, encoding: "utf-8" });
|
|
1816
|
+
return entries.filter((entry) => regex.test(entry.replace(/\\/g, "/"))).map((entry) => path9.join(baseDir, entry)).filter((fullPath) => fs9.statSync(fullPath).isFile());
|
|
1892
1817
|
}
|
|
1893
1818
|
var testCommand = new Command10("test").description("Run Quality Protocol test scenarios against a running server").argument("[files]", 'Glob pattern for test files (e.g. "qa/*.test.json")', "qa/*.test.json").option("--url <url>", "Target base URL", "http://localhost:3000").option("--token <token>", "Authentication token").action(async (filesPattern, options) => {
|
|
1894
|
-
console.log(
|
|
1819
|
+
console.log(chalk10.bold(`
|
|
1895
1820
|
\u{1F9EA} ObjectStack Quality Protocol Runner`));
|
|
1896
|
-
console.log(
|
|
1897
|
-
console.log(`Target: ${
|
|
1821
|
+
console.log(chalk10.dim(`-------------------------------------`));
|
|
1822
|
+
console.log(`Target: ${chalk10.blue(options.url)}`);
|
|
1898
1823
|
const adapter = new CoreQA.HttpTestAdapter(options.url, options.token);
|
|
1899
1824
|
const runner = new CoreQA.TestRunner(adapter);
|
|
1900
1825
|
const testFiles = resolveGlob(filesPattern);
|
|
1901
1826
|
if (testFiles.length === 0) {
|
|
1902
|
-
console.warn(
|
|
1827
|
+
console.warn(chalk10.yellow(`No test files found matching: ${filesPattern}`));
|
|
1903
1828
|
return;
|
|
1904
1829
|
}
|
|
1905
1830
|
console.log(`Found ${testFiles.length} test suites.`);
|
|
@@ -1907,19 +1832,19 @@ var testCommand = new Command10("test").description("Run Quality Protocol test s
|
|
|
1907
1832
|
let totalFailed = 0;
|
|
1908
1833
|
for (const file of testFiles) {
|
|
1909
1834
|
console.log(`
|
|
1910
|
-
\u{1F4C4} Running suite: ${
|
|
1835
|
+
\u{1F4C4} Running suite: ${chalk10.bold(path9.basename(file))}`);
|
|
1911
1836
|
try {
|
|
1912
|
-
const content =
|
|
1837
|
+
const content = fs9.readFileSync(file, "utf-8");
|
|
1913
1838
|
const suite = JSON.parse(content);
|
|
1914
1839
|
const results = await runner.runSuite(suite);
|
|
1915
1840
|
for (const result of results) {
|
|
1916
1841
|
const icon = result.passed ? "\u2705" : "\u274C";
|
|
1917
1842
|
console.log(` ${icon} Scenario: ${result.scenarioId} (${result.duration}ms)`);
|
|
1918
1843
|
if (!result.passed) {
|
|
1919
|
-
console.error(
|
|
1844
|
+
console.error(chalk10.red(` Error: ${result.error}`));
|
|
1920
1845
|
result.steps.forEach((step) => {
|
|
1921
1846
|
if (!step.passed) {
|
|
1922
|
-
console.error(
|
|
1847
|
+
console.error(chalk10.red(` Step Failed: ${step.stepName}`));
|
|
1923
1848
|
if (step.output) console.error(` Output:`, step.output);
|
|
1924
1849
|
if (step.error) console.error(` Error:`, step.error);
|
|
1925
1850
|
}
|
|
@@ -1930,27 +1855,27 @@ var testCommand = new Command10("test").description("Run Quality Protocol test s
|
|
|
1930
1855
|
}
|
|
1931
1856
|
}
|
|
1932
1857
|
} catch (e) {
|
|
1933
|
-
console.error(
|
|
1858
|
+
console.error(chalk10.red(`Failed to load or run suite ${file}: ${e}`));
|
|
1934
1859
|
totalFailed++;
|
|
1935
1860
|
}
|
|
1936
1861
|
}
|
|
1937
|
-
console.log(
|
|
1862
|
+
console.log(chalk10.dim(`
|
|
1938
1863
|
-------------------------------------`));
|
|
1939
1864
|
if (totalFailed > 0) {
|
|
1940
|
-
console.log(
|
|
1865
|
+
console.log(chalk10.red(`FAILED: ${totalFailed} scenarios failed. ${totalPassed} passed.`));
|
|
1941
1866
|
process.exit(1);
|
|
1942
1867
|
} else {
|
|
1943
|
-
console.log(
|
|
1868
|
+
console.log(chalk10.green(`SUCCESS: All ${totalPassed} scenarios passed.`));
|
|
1944
1869
|
process.exit(0);
|
|
1945
1870
|
}
|
|
1946
1871
|
});
|
|
1947
1872
|
|
|
1948
1873
|
// src/commands/doctor.ts
|
|
1949
1874
|
import { Command as Command11 } from "commander";
|
|
1950
|
-
import
|
|
1875
|
+
import chalk11 from "chalk";
|
|
1951
1876
|
import { execSync as execSync2 } from "child_process";
|
|
1952
|
-
import
|
|
1953
|
-
import
|
|
1877
|
+
import fs10 from "fs";
|
|
1878
|
+
import path10 from "path";
|
|
1954
1879
|
var doctorCommand = new Command11("doctor").description("Check development environment health").option("-v, --verbose", "Show detailed information").action(async (options) => {
|
|
1955
1880
|
printHeader("Environment Health Check");
|
|
1956
1881
|
const results = [];
|
|
@@ -2010,8 +1935,8 @@ var doctorCommand = new Command11("doctor").description("Check development envir
|
|
|
2010
1935
|
});
|
|
2011
1936
|
}
|
|
2012
1937
|
const cwd = process.cwd();
|
|
2013
|
-
const nodeModulesPath =
|
|
2014
|
-
if (
|
|
1938
|
+
const nodeModulesPath = path10.join(cwd, "node_modules");
|
|
1939
|
+
if (fs10.existsSync(nodeModulesPath)) {
|
|
2015
1940
|
results.push({
|
|
2016
1941
|
name: "Dependencies",
|
|
2017
1942
|
status: "ok",
|
|
@@ -2025,8 +1950,8 @@ var doctorCommand = new Command11("doctor").description("Check development envir
|
|
|
2025
1950
|
fix: "Run: pnpm install"
|
|
2026
1951
|
});
|
|
2027
1952
|
}
|
|
2028
|
-
const specDistPath =
|
|
2029
|
-
if (
|
|
1953
|
+
const specDistPath = path10.join(cwd, "packages/spec/dist");
|
|
1954
|
+
if (fs10.existsSync(specDistPath)) {
|
|
2030
1955
|
results.push({
|
|
2031
1956
|
name: "@objectstack/spec",
|
|
2032
1957
|
status: "ok",
|
|
@@ -2068,27 +1993,27 @@ var doctorCommand = new Command11("doctor").description("Check development envir
|
|
|
2068
1993
|
printError(`${padded} ${result.message}`);
|
|
2069
1994
|
}
|
|
2070
1995
|
if (result.fix && (options.verbose || result.status === "error")) {
|
|
2071
|
-
console.log(
|
|
1996
|
+
console.log(chalk11.dim(` \u2192 ${result.fix}`));
|
|
2072
1997
|
}
|
|
2073
1998
|
if (result.status === "error") hasErrors = true;
|
|
2074
1999
|
if (result.status === "warning") hasWarnings = true;
|
|
2075
2000
|
});
|
|
2076
2001
|
console.log("");
|
|
2077
2002
|
if (hasErrors) {
|
|
2078
|
-
console.log(
|
|
2079
|
-
results.filter((r) => r.status === "error" && r.fix).forEach((r) => console.log(
|
|
2003
|
+
console.log(chalk11.red("\u274C Some critical issues found. Please fix them before continuing."));
|
|
2004
|
+
results.filter((r) => r.status === "error" && r.fix).forEach((r) => console.log(chalk11.dim(` ${r.fix}`)));
|
|
2080
2005
|
process.exit(1);
|
|
2081
2006
|
} else if (hasWarnings) {
|
|
2082
|
-
console.log(
|
|
2083
|
-
console.log(
|
|
2007
|
+
console.log(chalk11.yellow("\u26A0\uFE0F Environment is functional but has some warnings."));
|
|
2008
|
+
console.log(chalk11.dim(" Run with --verbose to see fix suggestions."));
|
|
2084
2009
|
} else {
|
|
2085
|
-
console.log(
|
|
2010
|
+
console.log(chalk11.green("\u2705 Environment is healthy and ready for development!"));
|
|
2086
2011
|
}
|
|
2087
2012
|
console.log("");
|
|
2088
2013
|
});
|
|
2089
2014
|
|
|
2090
2015
|
// src/utils/plugin-commands.ts
|
|
2091
|
-
import
|
|
2016
|
+
import chalk12 from "chalk";
|
|
2092
2017
|
async function loadPluginCommands(program) {
|
|
2093
2018
|
let config;
|
|
2094
2019
|
try {
|
|
@@ -2132,7 +2057,7 @@ async function loadPluginCommands(program) {
|
|
|
2132
2057
|
if (process.env.DEBUG) {
|
|
2133
2058
|
const message = error instanceof Error ? error.message : String(error);
|
|
2134
2059
|
console.error(
|
|
2135
|
-
|
|
2060
|
+
chalk12.yellow(` \u26A0 Failed to load CLI command '${contribution.name}' from plugin '${contribution.pluginName}': ${message}`)
|
|
2136
2061
|
);
|
|
2137
2062
|
}
|
|
2138
2063
|
}
|