@objectstack/cli 2.0.6 → 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/dist/bin.js CHANGED
@@ -1,244 +1,32 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ collectMetadataStats,
4
+ createTimer,
5
+ formatZodErrors,
6
+ loadConfig,
7
+ printError,
8
+ printHeader,
9
+ printInfo,
10
+ printKV,
11
+ printMetadataStats,
12
+ printServerReady,
13
+ printStep,
14
+ printSuccess,
15
+ printWarning,
16
+ resolveConfigPath
17
+ } from "./chunk-Q74JNWKD.js";
2
18
 
3
19
  // src/bin.ts
4
20
  import { createRequire as createRequire2 } from "module";
5
- import { Command as Command12 } from "commander";
21
+ import { Command as Command13 } from "commander";
6
22
  import chalk13 from "chalk";
7
23
 
8
24
  // src/commands/compile.ts
9
25
  import { Command } from "commander";
10
- import path2 from "path";
11
- import fs2 from "fs";
12
- import chalk3 from "chalk";
13
- import { ObjectStackDefinitionSchema } from "@objectstack/spec";
14
-
15
- // src/utils/config.ts
16
26
  import path from "path";
17
27
  import fs from "fs";
18
- import chalk2 from "chalk";
19
- import { bundleRequire } from "bundle-require";
20
-
21
- // src/utils/format.ts
22
28
  import chalk from "chalk";
23
- function printHeader(title) {
24
- console.log(chalk.bold(`
25
- \u25C6 ${title}`));
26
- console.log(chalk.dim("\u2500".repeat(40)));
27
- }
28
- function printKV(key, value, icon) {
29
- const prefix = icon ? `${icon} ` : " ";
30
- console.log(`${prefix}${chalk.dim(key + ":")} ${chalk.white(String(value))}`);
31
- }
32
- function printSuccess(msg) {
33
- console.log(chalk.green(` \u2713 ${msg}`));
34
- }
35
- function printWarning(msg) {
36
- console.log(chalk.yellow(` \u26A0 ${msg}`));
37
- }
38
- function printError(msg) {
39
- console.log(chalk.red(` \u2717 ${msg}`));
40
- }
41
- function printInfo(msg) {
42
- console.log(chalk.blue(` \u2139 ${msg}`));
43
- }
44
- function printStep(msg) {
45
- console.log(chalk.yellow(` \u2192 ${msg}`));
46
- }
47
- function createTimer() {
48
- const start = Date.now();
49
- return {
50
- elapsed: () => Date.now() - start,
51
- display: () => `${Date.now() - start}ms`
52
- };
53
- }
54
- function formatZodErrors(error) {
55
- const issues = error.issues || error.errors || [];
56
- if (issues.length === 0) {
57
- console.log(chalk.red(" Unknown validation error"));
58
- return;
59
- }
60
- const grouped = /* @__PURE__ */ new Map();
61
- for (const issue of issues) {
62
- const topPath = issue.path?.[0] || "_root";
63
- if (!grouped.has(String(topPath))) {
64
- grouped.set(String(topPath), []);
65
- }
66
- grouped.get(String(topPath)).push(issue);
67
- }
68
- for (const [section, sectionIssues] of grouped) {
69
- console.log(chalk.bold.red(`
70
- ${section}:`));
71
- for (const issue of sectionIssues) {
72
- const path11 = issue.path?.join(".") || "";
73
- const code = issue.code || "";
74
- const msg = issue.message || "";
75
- console.log(chalk.red(` \u2717 ${path11}`));
76
- console.log(chalk.dim(` ${code}: ${msg}`));
77
- if (issue.expected) {
78
- console.log(chalk.dim(` expected: ${chalk.green(issue.expected)}`));
79
- }
80
- if (issue.received) {
81
- console.log(chalk.dim(` received: ${chalk.red(issue.received)}`));
82
- }
83
- }
84
- }
85
- console.log("");
86
- console.log(chalk.dim(` ${issues.length} validation error(s) total`));
87
- }
88
- function collectMetadataStats(config) {
89
- const count = (arr) => Array.isArray(arr) ? arr.length : 0;
90
- let fields = 0;
91
- if (Array.isArray(config.objects)) {
92
- for (const obj of config.objects) {
93
- if (obj.fields && typeof obj.fields === "object") {
94
- fields += Object.keys(obj.fields).length;
95
- }
96
- }
97
- }
98
- return {
99
- objects: count(config.objects),
100
- objectExtensions: count(config.objectExtensions),
101
- fields,
102
- views: count(config.views),
103
- pages: count(config.pages),
104
- apps: count(config.apps),
105
- dashboards: count(config.dashboards),
106
- reports: count(config.reports),
107
- actions: count(config.actions),
108
- flows: count(config.flows),
109
- workflows: count(config.workflows),
110
- approvals: count(config.approvals),
111
- agents: count(config.agents),
112
- apis: count(config.apis),
113
- roles: count(config.roles),
114
- permissions: count(config.permissions),
115
- themes: count(config.themes),
116
- datasources: count(config.datasources),
117
- translations: count(config.translations),
118
- plugins: count(config.plugins),
119
- devPlugins: count(config.devPlugins)
120
- };
121
- }
122
- function printServerReady(opts) {
123
- const base = `http://localhost:${opts.port}`;
124
- console.log("");
125
- console.log(chalk.bold.green(" \u2713 Server is ready"));
126
- console.log("");
127
- console.log(chalk.cyan(" \u279C") + chalk.bold(" API: ") + chalk.cyan(base + "/"));
128
- if (opts.uiEnabled && opts.studioPath) {
129
- console.log(chalk.cyan(" \u279C") + chalk.bold(" Studio: ") + chalk.cyan(base + opts.studioPath + "/"));
130
- }
131
- console.log("");
132
- console.log(chalk.dim(` Config: ${opts.configFile}`));
133
- console.log(chalk.dim(` Mode: ${opts.isDev ? "development" : "production"}`));
134
- console.log(chalk.dim(` Plugins: ${opts.pluginCount} loaded`));
135
- if (opts.pluginNames && opts.pluginNames.length > 0) {
136
- console.log(chalk.dim(` ${opts.pluginNames.join(", ")}`));
137
- }
138
- console.log("");
139
- console.log(chalk.dim(" Press Ctrl+C to stop"));
140
- console.log("");
141
- }
142
- function printMetadataStats(stats) {
143
- const sections = [
144
- {
145
- label: "Data",
146
- items: [
147
- ["Objects", stats.objects],
148
- ["Fields", stats.fields],
149
- ["Extensions", stats.objectExtensions],
150
- ["Datasources", stats.datasources]
151
- ]
152
- },
153
- {
154
- label: "UI",
155
- items: [
156
- ["Apps", stats.apps],
157
- ["Views", stats.views],
158
- ["Pages", stats.pages],
159
- ["Dashboards", stats.dashboards],
160
- ["Reports", stats.reports],
161
- ["Actions", stats.actions],
162
- ["Themes", stats.themes]
163
- ]
164
- },
165
- {
166
- label: "Logic",
167
- items: [
168
- ["Flows", stats.flows],
169
- ["Workflows", stats.workflows],
170
- ["Approvals", stats.approvals],
171
- ["Agents", stats.agents],
172
- ["APIs", stats.apis]
173
- ]
174
- },
175
- {
176
- label: "Security",
177
- items: [
178
- ["Roles", stats.roles],
179
- ["Permissions", stats.permissions]
180
- ]
181
- }
182
- ];
183
- for (const section of sections) {
184
- const nonZero = section.items.filter(([, v]) => v > 0);
185
- if (nonZero.length === 0) continue;
186
- const line = nonZero.map(([k, v]) => `${chalk.white(v)} ${chalk.dim(k)}`).join(" ");
187
- console.log(` ${chalk.bold(section.label + ":")} ${line}`);
188
- }
189
- if (stats.plugins > 0 || stats.devPlugins > 0) {
190
- const parts = [];
191
- if (stats.plugins > 0) parts.push(`${stats.plugins} plugins`);
192
- if (stats.devPlugins > 0) parts.push(`${stats.devPlugins} devPlugins`);
193
- console.log(` ${chalk.bold("Runtime:")} ${chalk.dim(parts.join(", "))}`);
194
- }
195
- }
196
-
197
- // src/utils/config.ts
198
- function resolveConfigPath(source) {
199
- if (source) {
200
- const abs = path.resolve(process.cwd(), source);
201
- if (!fs.existsSync(abs)) {
202
- printError(`Config file not found: ${chalk2.white(abs)}`);
203
- console.log("");
204
- console.log(chalk2.dim(" Hint: Run this command from a directory with objectstack.config.ts"));
205
- console.log(chalk2.dim(" Or specify the path: objectstack <command> path/to/config.ts"));
206
- process.exit(1);
207
- }
208
- return abs;
209
- }
210
- const candidates = [
211
- "objectstack.config.ts",
212
- "objectstack.config.js",
213
- "objectstack.config.mjs"
214
- ];
215
- for (const candidate of candidates) {
216
- const abs = path.resolve(process.cwd(), candidate);
217
- if (fs.existsSync(abs)) return abs;
218
- }
219
- printError("No objectstack.config.{ts,js,mjs} found in current directory");
220
- console.log("");
221
- console.log(chalk2.dim(" Hint: Run `objectstack init` to create a new project"));
222
- process.exit(1);
223
- }
224
- async function loadConfig(source) {
225
- const absolutePath = resolveConfigPath(source);
226
- const start = Date.now();
227
- const { mod } = await bundleRequire({
228
- filepath: absolutePath
229
- });
230
- const config = mod.default || mod;
231
- if (!config) {
232
- throw new Error(`No default export found in ${path.basename(absolutePath)}`);
233
- }
234
- return {
235
- config,
236
- absolutePath,
237
- duration: Date.now() - start
238
- };
239
- }
240
-
241
- // src/commands/compile.ts
29
+ import { ObjectStackDefinitionSchema } from "@objectstack/spec";
242
30
  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) => {
243
31
  const timer = createTimer();
244
32
  if (!options.json) {
@@ -248,7 +36,7 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
248
36
  if (!options.json) printStep("Loading configuration...");
249
37
  const { config, absolutePath, duration } = await loadConfig(configPath);
250
38
  if (!options.json) {
251
- printKV("Config", path2.relative(process.cwd(), absolutePath));
39
+ printKV("Config", path.relative(process.cwd(), absolutePath));
252
40
  printKV("Load time", `${duration}ms`);
253
41
  }
254
42
  if (!options.json) printStep("Validating protocol compliance...");
@@ -265,13 +53,13 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
265
53
  }
266
54
  if (!options.json) printStep("Writing artifact...");
267
55
  const output = options.output;
268
- const artifactPath = path2.resolve(process.cwd(), output);
269
- const artifactDir = path2.dirname(artifactPath);
270
- if (!fs2.existsSync(artifactDir)) {
271
- fs2.mkdirSync(artifactDir, { recursive: true });
56
+ const artifactPath = path.resolve(process.cwd(), output);
57
+ const artifactDir = path.dirname(artifactPath);
58
+ if (!fs.existsSync(artifactDir)) {
59
+ fs.mkdirSync(artifactDir, { recursive: true });
272
60
  }
273
61
  const jsonContent = JSON.stringify(result.data, null, 2);
274
- fs2.writeFileSync(artifactPath, jsonContent);
62
+ fs.writeFileSync(artifactPath, jsonContent);
275
63
  const sizeKB = (jsonContent.length / 1024).toFixed(1);
276
64
  const stats = collectMetadataStats(config);
277
65
  if (options.json) {
@@ -285,11 +73,11 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
285
73
  return;
286
74
  }
287
75
  console.log("");
288
- printSuccess(`Build complete ${chalk3.dim(`(${timer.display()})`)}`);
76
+ printSuccess(`Build complete ${chalk.dim(`(${timer.display()})`)}`);
289
77
  console.log("");
290
78
  printMetadataStats(stats);
291
79
  console.log("");
292
- printKV("Artifact", `${output} ${chalk3.dim(`(${sizeKB} KB`)})`);
80
+ printKV("Artifact", `${output} ${chalk.dim(`(${sizeKB} KB`)})`);
293
81
  console.log("");
294
82
  } catch (error) {
295
83
  if (options.json) {
@@ -304,14 +92,14 @@ var compileCommand = new Command("compile").description("Compile ObjectStack con
304
92
 
305
93
  // src/commands/dev.ts
306
94
  import { Command as Command2 } from "commander";
307
- import chalk4 from "chalk";
95
+ import chalk2 from "chalk";
308
96
  import { execSync, spawn } from "child_process";
309
- import fs3 from "fs";
310
- import path3 from "path";
97
+ import fs2 from "fs";
98
+ import path2 from "path";
311
99
  var devCommand = new Command2("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) => {
312
100
  printHeader("Development Mode");
313
- const configPath = path3.resolve(process.cwd(), "objectstack.config.ts");
314
- if (packageName === "all" && fs3.existsSync(configPath)) {
101
+ const configPath = path2.resolve(process.cwd(), "objectstack.config.ts");
102
+ if (packageName === "all" && fs2.existsSync(configPath)) {
315
103
  printKV("Config", configPath, "\u{1F4C2}");
316
104
  printStep("Starting dev server...");
317
105
  const binPath = process.argv[1];
@@ -323,18 +111,18 @@ var devCommand = new Command2("dev").description("Start development mode with ho
323
111
  }
324
112
  try {
325
113
  const cwd = process.cwd();
326
- const workspaceConfigPath = path3.resolve(cwd, "pnpm-workspace.yaml");
327
- const isWorkspaceRoot = fs3.existsSync(workspaceConfigPath);
114
+ const workspaceConfigPath = path2.resolve(cwd, "pnpm-workspace.yaml");
115
+ const isWorkspaceRoot = fs2.existsSync(workspaceConfigPath);
328
116
  if (packageName === "all" && !isWorkspaceRoot) {
329
117
  printError(`Config file not found in ${cwd}`);
330
- console.error(chalk4.yellow(" Run in a directory with objectstack.config.ts, or from the monorepo root."));
118
+ console.error(chalk2.yellow(" Run in a directory with objectstack.config.ts, or from the monorepo root."));
331
119
  process.exit(1);
332
120
  }
333
121
  const filter = packageName === "all" ? "" : `--filter ${packageName}`;
334
122
  printKV("Package", packageName === "all" ? "All packages" : packageName, "\u{1F4E6}");
335
123
  printKV("Watch", "enabled", "\u{1F504}");
336
124
  const command = `pnpm ${filter} dev`.trim();
337
- console.log(chalk4.dim(`$ ${command}`));
125
+ console.log(chalk2.dim(`$ ${command}`));
338
126
  console.log("");
339
127
  execSync(command, {
340
128
  stdio: "inherit",
@@ -348,10 +136,10 @@ var devCommand = new Command2("dev").description("Start development mode with ho
348
136
 
349
137
  // src/commands/doctor.ts
350
138
  import { Command as Command3 } from "commander";
351
- import chalk5 from "chalk";
139
+ import chalk3 from "chalk";
352
140
  import { execSync as execSync2 } from "child_process";
353
- import fs4 from "fs";
354
- import path4 from "path";
141
+ import fs3 from "fs";
142
+ import path3 from "path";
355
143
  var doctorCommand = new Command3("doctor").description("Check development environment health").option("-v, --verbose", "Show detailed information").action(async (options) => {
356
144
  printHeader("Environment Health Check");
357
145
  const results = [];
@@ -411,8 +199,8 @@ var doctorCommand = new Command3("doctor").description("Check development enviro
411
199
  });
412
200
  }
413
201
  const cwd = process.cwd();
414
- const nodeModulesPath = path4.join(cwd, "node_modules");
415
- if (fs4.existsSync(nodeModulesPath)) {
202
+ const nodeModulesPath = path3.join(cwd, "node_modules");
203
+ if (fs3.existsSync(nodeModulesPath)) {
416
204
  results.push({
417
205
  name: "Dependencies",
418
206
  status: "ok",
@@ -426,8 +214,8 @@ var doctorCommand = new Command3("doctor").description("Check development enviro
426
214
  fix: "Run: pnpm install"
427
215
  });
428
216
  }
429
- const specDistPath = path4.join(cwd, "packages/spec/dist");
430
- if (fs4.existsSync(specDistPath)) {
217
+ const specDistPath = path3.join(cwd, "packages/spec/dist");
218
+ if (fs3.existsSync(specDistPath)) {
431
219
  results.push({
432
220
  name: "@objectstack/spec",
433
221
  status: "ok",
@@ -469,30 +257,30 @@ var doctorCommand = new Command3("doctor").description("Check development enviro
469
257
  printError(`${padded} ${result.message}`);
470
258
  }
471
259
  if (result.fix && (options.verbose || result.status === "error")) {
472
- console.log(chalk5.dim(` \u2192 ${result.fix}`));
260
+ console.log(chalk3.dim(` \u2192 ${result.fix}`));
473
261
  }
474
262
  if (result.status === "error") hasErrors = true;
475
263
  if (result.status === "warning") hasWarnings = true;
476
264
  });
477
265
  console.log("");
478
266
  if (hasErrors) {
479
- console.log(chalk5.red("\u274C Some critical issues found. Please fix them before continuing."));
480
- results.filter((r) => r.status === "error" && r.fix).forEach((r) => console.log(chalk5.dim(` ${r.fix}`)));
267
+ console.log(chalk3.red("\u274C Some critical issues found. Please fix them before continuing."));
268
+ results.filter((r) => r.status === "error" && r.fix).forEach((r) => console.log(chalk3.dim(` ${r.fix}`)));
481
269
  process.exit(1);
482
270
  } else if (hasWarnings) {
483
- console.log(chalk5.yellow("\u26A0\uFE0F Environment is functional but has some warnings."));
484
- console.log(chalk5.dim(" Run with --verbose to see fix suggestions."));
271
+ console.log(chalk3.yellow("\u26A0\uFE0F Environment is functional but has some warnings."));
272
+ console.log(chalk3.dim(" Run with --verbose to see fix suggestions."));
485
273
  } else {
486
- console.log(chalk5.green("\u2705 Environment is healthy and ready for development!"));
274
+ console.log(chalk3.green("\u2705 Environment is healthy and ready for development!"));
487
275
  }
488
276
  console.log("");
489
277
  });
490
278
 
491
279
  // src/commands/create.ts
492
280
  import { Command as Command4 } from "commander";
493
- import chalk6 from "chalk";
494
- import fs5 from "fs";
495
- import path5 from "path";
281
+ import chalk4 from "chalk";
282
+ import fs4 from "fs";
283
+ import path4 from "path";
496
284
  var templates = {
497
285
  plugin: {
498
286
  description: "Create a new ObjectStack plugin",
@@ -667,64 +455,64 @@ function toCamelCase(str) {
667
455
  return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
668
456
  }
669
457
  var createCommand = new Command4("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) => {
670
- console.log(chalk6.bold(`
458
+ console.log(chalk4.bold(`
671
459
  \u{1F4E6} ObjectStack Project Creator`));
672
- console.log(chalk6.dim(`-------------------------------`));
460
+ console.log(chalk4.dim(`-------------------------------`));
673
461
  if (!templates[type]) {
674
- console.error(chalk6.red(`
462
+ console.error(chalk4.red(`
675
463
  \u274C Unknown type: ${type}`));
676
- console.log(chalk6.dim("Available types: plugin, example"));
464
+ console.log(chalk4.dim("Available types: plugin, example"));
677
465
  process.exit(1);
678
466
  }
679
467
  if (!name) {
680
- console.error(chalk6.red("\n\u274C Project name is required"));
681
- console.log(chalk6.dim(`Usage: objectstack create ${type} <name>`));
468
+ console.error(chalk4.red("\n\u274C Project name is required"));
469
+ console.log(chalk4.dim(`Usage: objectstack create ${type} <name>`));
682
470
  process.exit(1);
683
471
  }
684
472
  const template = templates[type];
685
473
  const cwd = process.cwd();
686
474
  let targetDir;
687
475
  if (options?.dir) {
688
- targetDir = path5.resolve(cwd, options.dir);
476
+ targetDir = path4.resolve(cwd, options.dir);
689
477
  } else {
690
478
  const baseDir = type === "plugin" ? "packages/plugins" : "examples";
691
479
  const projectName = type === "plugin" ? `plugin-${name}` : name;
692
- targetDir = path5.join(cwd, baseDir, projectName);
480
+ targetDir = path4.join(cwd, baseDir, projectName);
693
481
  }
694
- if (fs5.existsSync(targetDir)) {
695
- console.error(chalk6.red(`
482
+ if (fs4.existsSync(targetDir)) {
483
+ console.error(chalk4.red(`
696
484
  \u274C Directory already exists: ${targetDir}`));
697
485
  process.exit(1);
698
486
  }
699
- console.log(`\u{1F4C1} Creating ${type}: ${chalk6.blue(name)}`);
700
- console.log(`\u{1F4C2} Location: ${chalk6.dim(targetDir)}`);
487
+ console.log(`\u{1F4C1} Creating ${type}: ${chalk4.blue(name)}`);
488
+ console.log(`\u{1F4C2} Location: ${chalk4.dim(targetDir)}`);
701
489
  console.log("");
702
490
  try {
703
- fs5.mkdirSync(targetDir, { recursive: true });
491
+ fs4.mkdirSync(targetDir, { recursive: true });
704
492
  for (const [filePath, contentFn] of Object.entries(template.files)) {
705
- const fullPath = path5.join(targetDir, filePath);
706
- const dir = path5.dirname(fullPath);
707
- if (!fs5.existsSync(dir)) {
708
- fs5.mkdirSync(dir, { recursive: true });
493
+ const fullPath = path4.join(targetDir, filePath);
494
+ const dir = path4.dirname(fullPath);
495
+ if (!fs4.existsSync(dir)) {
496
+ fs4.mkdirSync(dir, { recursive: true });
709
497
  }
710
498
  const content = contentFn(name);
711
499
  const fileContent = typeof content === "string" ? content : JSON.stringify(content, null, 2);
712
- fs5.writeFileSync(fullPath, fileContent);
713
- console.log(chalk6.green(`\u2713 Created ${filePath}`));
500
+ fs4.writeFileSync(fullPath, fileContent);
501
+ console.log(chalk4.green(`\u2713 Created ${filePath}`));
714
502
  }
715
503
  console.log("");
716
- console.log(chalk6.green("\u2705 Project created successfully!"));
504
+ console.log(chalk4.green("\u2705 Project created successfully!"));
717
505
  console.log("");
718
- console.log(chalk6.bold("Next steps:"));
719
- console.log(chalk6.dim(` cd ${path5.relative(cwd, targetDir)}`));
720
- console.log(chalk6.dim(" pnpm install"));
721
- console.log(chalk6.dim(" pnpm build"));
506
+ console.log(chalk4.bold("Next steps:"));
507
+ console.log(chalk4.dim(` cd ${path4.relative(cwd, targetDir)}`));
508
+ console.log(chalk4.dim(" pnpm install"));
509
+ console.log(chalk4.dim(" pnpm build"));
722
510
  console.log("");
723
511
  } catch (error) {
724
- console.error(chalk6.red("\n\u274C Failed to create project:"));
512
+ console.error(chalk4.red("\n\u274C Failed to create project:"));
725
513
  console.error(error.message || error);
726
- if (fs5.existsSync(targetDir)) {
727
- fs5.rmSync(targetDir, { recursive: true });
514
+ if (fs4.existsSync(targetDir)) {
515
+ fs4.rmSync(targetDir, { recursive: true });
728
516
  }
729
517
  process.exit(1);
730
518
  }
@@ -732,37 +520,37 @@ var createCommand = new Command4("create").description("Create a new package, pl
732
520
 
733
521
  // src/commands/serve.ts
734
522
  import { Command as Command5 } from "commander";
735
- import path7 from "path";
736
- import fs7 from "fs";
523
+ import path6 from "path";
524
+ import fs6 from "fs";
737
525
  import net from "net";
738
- import chalk7 from "chalk";
739
- import { bundleRequire as bundleRequire2 } from "bundle-require";
526
+ import chalk5 from "chalk";
527
+ import { bundleRequire } from "bundle-require";
740
528
 
741
529
  // src/utils/studio.ts
742
- import path6 from "path";
743
- import fs6 from "fs";
530
+ import path5 from "path";
531
+ import fs5 from "fs";
744
532
  import { createRequire } from "module";
745
533
  import { pathToFileURL } from "url";
746
534
  var STUDIO_PATH = "/_studio";
747
535
  function resolveStudioPath() {
748
536
  const cwd = process.cwd();
749
537
  const candidates = [
750
- path6.resolve(cwd, "apps/studio"),
751
- path6.resolve(cwd, "../../apps/studio"),
752
- path6.resolve(cwd, "../apps/studio")
538
+ path5.resolve(cwd, "apps/studio"),
539
+ path5.resolve(cwd, "../../apps/studio"),
540
+ path5.resolve(cwd, "../apps/studio")
753
541
  ];
754
542
  for (const candidate of candidates) {
755
- const pkgPath = path6.join(candidate, "package.json");
756
- if (fs6.existsSync(pkgPath)) {
543
+ const pkgPath = path5.join(candidate, "package.json");
544
+ if (fs5.existsSync(pkgPath)) {
757
545
  try {
758
- const pkg2 = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
546
+ const pkg2 = JSON.parse(fs5.readFileSync(pkgPath, "utf-8"));
759
547
  if (pkg2.name === "@objectstack/studio") return candidate;
760
548
  } catch {
761
549
  }
762
550
  }
763
551
  }
764
552
  const resolutionBases = [
765
- pathToFileURL(path6.join(cwd, "package.json")).href,
553
+ pathToFileURL(path5.join(cwd, "package.json")).href,
766
554
  // consumer workspace
767
555
  import.meta.url
768
556
  // CLI package itself
@@ -771,18 +559,18 @@ function resolveStudioPath() {
771
559
  try {
772
560
  const req = createRequire(base);
773
561
  const resolved = req.resolve("@objectstack/studio/package.json");
774
- return path6.dirname(resolved);
562
+ return path5.dirname(resolved);
775
563
  } catch {
776
564
  }
777
565
  }
778
- const directPath = path6.join(cwd, "node_modules", "@objectstack", "studio");
779
- if (fs6.existsSync(path6.join(directPath, "package.json"))) {
566
+ const directPath = path5.join(cwd, "node_modules", "@objectstack", "studio");
567
+ if (fs5.existsSync(path5.join(directPath, "package.json"))) {
780
568
  return directPath;
781
569
  }
782
570
  return null;
783
571
  }
784
572
  function hasStudioDist(studioPath) {
785
- return fs6.existsSync(path6.join(studioPath, "dist", "index.html"));
573
+ return fs5.existsSync(path5.join(studioPath, "dist", "index.html"));
786
574
  }
787
575
  function createStudioStaticPlugin(distPath, options) {
788
576
  return {
@@ -796,13 +584,13 @@ function createStudioStaticPlugin(distPath, options) {
796
584
  return;
797
585
  }
798
586
  const app = httpServer.getRawApp();
799
- const absoluteDist = path6.resolve(distPath);
800
- const indexPath = path6.join(absoluteDist, "index.html");
801
- if (!fs6.existsSync(indexPath)) {
587
+ const absoluteDist = path5.resolve(distPath);
588
+ const indexPath = path5.join(absoluteDist, "index.html");
589
+ if (!fs5.existsSync(indexPath)) {
802
590
  ctx.logger?.warn?.(`Studio static: dist not found at ${absoluteDist}`);
803
591
  return;
804
592
  }
805
- const rawHtml = fs6.readFileSync(indexPath, "utf-8");
593
+ const rawHtml = fs5.readFileSync(indexPath, "utf-8");
806
594
  const rewrittenHtml = rawHtml.replace(
807
595
  /(\s(?:href|src))="\/(?!\/)/g,
808
596
  `$1="${STUDIO_PATH}/`
@@ -813,12 +601,12 @@ function createStudioStaticPlugin(distPath, options) {
813
601
  app.get(STUDIO_PATH, (c) => c.redirect(`${STUDIO_PATH}/`));
814
602
  app.get(`${STUDIO_PATH}/*`, async (c) => {
815
603
  const reqPath = c.req.path.substring(STUDIO_PATH.length) || "/";
816
- const filePath = path6.join(absoluteDist, reqPath);
604
+ const filePath = path5.join(absoluteDist, reqPath);
817
605
  if (!filePath.startsWith(absoluteDist)) {
818
606
  return c.text("Forbidden", 403);
819
607
  }
820
- if (fs6.existsSync(filePath) && fs6.statSync(filePath).isFile()) {
821
- const content = fs6.readFileSync(filePath);
608
+ if (fs5.existsSync(filePath) && fs5.statSync(filePath).isFile()) {
609
+ const content = fs5.readFileSync(filePath);
822
610
  return new Response(content, {
823
611
  headers: { "content-type": mimeType(filePath) }
824
612
  });
@@ -848,7 +636,7 @@ var MIME_TYPES = {
848
636
  ".map": "application/json"
849
637
  };
850
638
  function mimeType(filePath) {
851
- const ext = path6.extname(filePath).toLowerCase();
639
+ const ext = path5.extname(filePath).toLowerCase();
852
640
  return MIME_TYPES[ext] || "application/octet-stream";
853
641
  }
854
642
 
@@ -885,15 +673,15 @@ var serveCommand = new Command5("serve").description("Start ObjectStack server w
885
673
  } catch (e) {
886
674
  }
887
675
  const isDev = options.dev || process.env.NODE_ENV === "development";
888
- const absolutePath = path7.resolve(process.cwd(), configPath);
889
- const relativeConfig = path7.relative(process.cwd(), absolutePath);
890
- if (!fs7.existsSync(absolutePath)) {
676
+ const absolutePath = path6.resolve(process.cwd(), configPath);
677
+ const relativeConfig = path6.relative(process.cwd(), absolutePath);
678
+ if (!fs6.existsSync(absolutePath)) {
891
679
  printError(`Configuration file not found: ${absolutePath}`);
892
- console.log(chalk7.dim(" Hint: Run `objectstack init` to create a new project"));
680
+ console.log(chalk5.dim(" Hint: Run `objectstack init` to create a new project"));
893
681
  process.exit(1);
894
682
  }
895
683
  console.log("");
896
- console.log(chalk7.dim(` Loading ${relativeConfig}...`));
684
+ console.log(chalk5.dim(` Loading ${relativeConfig}...`));
897
685
  const loadedPlugins = [];
898
686
  const shortPluginName = (raw) => {
899
687
  if (raw.includes("objectql")) return "ObjectQL";
@@ -928,7 +716,7 @@ var serveCommand = new Command5("serve").description("Start ObjectStack server w
928
716
  console.debug = (...args) => {
929
717
  if (!bootQuiet) originalConsoleDebug(...args);
930
718
  };
931
- const { mod } = await bundleRequire2({
719
+ const { mod } = await bundleRequire({
932
720
  filepath: absolutePath
933
721
  });
934
722
  const config = mod.default || mod;
@@ -997,7 +785,7 @@ var serveCommand = new Command5("serve").description("Start ObjectStack server w
997
785
  const pluginName = plugin.name || plugin.constructor?.name || "unnamed";
998
786
  trackPlugin(pluginName);
999
787
  } catch (e) {
1000
- console.error(chalk7.red(` \u2717 Failed to load plugin: ${e.message}`));
788
+ console.error(chalk5.red(` \u2717 Failed to load plugin: ${e.message}`));
1001
789
  }
1002
790
  }
1003
791
  }
@@ -1008,7 +796,7 @@ var serveCommand = new Command5("serve").description("Start ObjectStack server w
1008
796
  await kernel.use(serverPlugin);
1009
797
  trackPlugin("HonoServer");
1010
798
  } catch (e) {
1011
- console.warn(chalk7.yellow(` \u26A0 HTTP server plugin not available: ${e.message}`));
799
+ console.warn(chalk5.yellow(` \u26A0 HTTP server plugin not available: ${e.message}`));
1012
800
  }
1013
801
  try {
1014
802
  const { createRestApiPlugin } = await import("@objectstack/rest");
@@ -1027,13 +815,13 @@ var serveCommand = new Command5("serve").description("Start ObjectStack server w
1027
815
  if (enableUI) {
1028
816
  const studioPath = resolveStudioPath();
1029
817
  if (!studioPath) {
1030
- console.warn(chalk7.yellow(` \u26A0 @objectstack/studio not found \u2014 skipping UI`));
818
+ console.warn(chalk5.yellow(` \u26A0 @objectstack/studio not found \u2014 skipping UI`));
1031
819
  } else if (hasStudioDist(studioPath)) {
1032
- const distPath = path7.join(studioPath, "dist");
820
+ const distPath = path6.join(studioPath, "dist");
1033
821
  await kernel.use(createStudioStaticPlugin(distPath, { isDev }));
1034
822
  trackPlugin("StudioUI");
1035
823
  } else {
1036
- console.warn(chalk7.yellow(` \u26A0 Studio dist not found \u2014 run "pnpm --filter @objectstack/studio build" first`));
824
+ console.warn(chalk5.yellow(` \u26A0 Studio dist not found \u2014 run "pnpm --filter @objectstack/studio build" first`));
1037
825
  }
1038
826
  }
1039
827
  await runtime.start();
@@ -1049,18 +837,18 @@ var serveCommand = new Command5("serve").description("Start ObjectStack server w
1049
837
  studioPath: STUDIO_PATH
1050
838
  });
1051
839
  process.on("SIGINT", async () => {
1052
- console.warn(chalk7.yellow(`
840
+ console.warn(chalk5.yellow(`
1053
841
 
1054
842
  \u23F9 Stopping server...`));
1055
843
  await runtime.getKernel().shutdown();
1056
- console.log(chalk7.green(`\u2705 Server stopped`));
844
+ console.log(chalk5.green(`\u2705 Server stopped`));
1057
845
  process.exit(0);
1058
846
  });
1059
847
  } catch (error) {
1060
848
  restoreOutput();
1061
849
  console.log("");
1062
850
  printError(error.message || String(error));
1063
- if (process.env.DEBUG) console.error(chalk7.dim(error.stack));
851
+ if (process.env.DEBUG) console.error(chalk5.dim(error.stack));
1064
852
  process.exit(1);
1065
853
  }
1066
854
  });
@@ -1092,15 +880,15 @@ var studioCommand = new Command6("studio").description("Launch Studio UI with de
1092
880
 
1093
881
  // src/commands/test.ts
1094
882
  import { Command as Command7 } from "commander";
1095
- import chalk8 from "chalk";
1096
- import path8 from "path";
1097
- import fs8 from "fs";
883
+ import chalk6 from "chalk";
884
+ import path7 from "path";
885
+ import fs7 from "fs";
1098
886
  import { QA as CoreQA } from "@objectstack/core";
1099
887
  function resolveGlob(pattern) {
1100
888
  if (!pattern.includes("*")) {
1101
- return fs8.existsSync(pattern) ? [pattern] : [];
889
+ return fs7.existsSync(pattern) ? [pattern] : [];
1102
890
  }
1103
- const parts = pattern.split(path8.sep.replace("\\", "/"));
891
+ const parts = pattern.split(path7.sep.replace("\\", "/"));
1104
892
  const segments = pattern.includes("/") ? pattern.split("/") : parts;
1105
893
  let baseDir = ".";
1106
894
  let globStart = 0;
@@ -1109,25 +897,25 @@ function resolveGlob(pattern) {
1109
897
  globStart = i;
1110
898
  break;
1111
899
  }
1112
- baseDir = i === 0 ? segments[i] : path8.join(baseDir, segments[i]);
900
+ baseDir = i === 0 ? segments[i] : path7.join(baseDir, segments[i]);
1113
901
  }
1114
- if (!fs8.existsSync(baseDir)) return [];
902
+ if (!fs7.existsSync(baseDir)) return [];
1115
903
  const globPortion = segments.slice(globStart).join("/");
1116
904
  const regexStr = globPortion.replace(/\./g, "\\.").replace(/\*\*\//g, "(.+/)?").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
1117
905
  const regex = new RegExp(`^${regexStr}$`);
1118
- const entries = fs8.readdirSync(baseDir, { recursive: true, encoding: "utf-8" });
1119
- return entries.filter((entry) => regex.test(entry.replace(/\\/g, "/"))).map((entry) => path8.join(baseDir, entry)).filter((fullPath) => fs8.statSync(fullPath).isFile());
906
+ const entries = fs7.readdirSync(baseDir, { recursive: true, encoding: "utf-8" });
907
+ return entries.filter((entry) => regex.test(entry.replace(/\\/g, "/"))).map((entry) => path7.join(baseDir, entry)).filter((fullPath) => fs7.statSync(fullPath).isFile());
1120
908
  }
1121
909
  var testCommand = new Command7("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) => {
1122
- console.log(chalk8.bold(`
910
+ console.log(chalk6.bold(`
1123
911
  \u{1F9EA} ObjectStack Quality Protocol Runner`));
1124
- console.log(chalk8.dim(`-------------------------------------`));
1125
- console.log(`Target: ${chalk8.blue(options.url)}`);
912
+ console.log(chalk6.dim(`-------------------------------------`));
913
+ console.log(`Target: ${chalk6.blue(options.url)}`);
1126
914
  const adapter = new CoreQA.HttpTestAdapter(options.url, options.token);
1127
915
  const runner = new CoreQA.TestRunner(adapter);
1128
916
  const testFiles = resolveGlob(filesPattern);
1129
917
  if (testFiles.length === 0) {
1130
- console.warn(chalk8.yellow(`No test files found matching: ${filesPattern}`));
918
+ console.warn(chalk6.yellow(`No test files found matching: ${filesPattern}`));
1131
919
  return;
1132
920
  }
1133
921
  console.log(`Found ${testFiles.length} test suites.`);
@@ -1135,19 +923,19 @@ var testCommand = new Command7("test").description("Run Quality Protocol test sc
1135
923
  let totalFailed = 0;
1136
924
  for (const file of testFiles) {
1137
925
  console.log(`
1138
- \u{1F4C4} Running suite: ${chalk8.bold(path8.basename(file))}`);
926
+ \u{1F4C4} Running suite: ${chalk6.bold(path7.basename(file))}`);
1139
927
  try {
1140
- const content = fs8.readFileSync(file, "utf-8");
928
+ const content = fs7.readFileSync(file, "utf-8");
1141
929
  const suite = JSON.parse(content);
1142
930
  const results = await runner.runSuite(suite);
1143
931
  for (const result of results) {
1144
932
  const icon = result.passed ? "\u2705" : "\u274C";
1145
933
  console.log(` ${icon} Scenario: ${result.scenarioId} (${result.duration}ms)`);
1146
934
  if (!result.passed) {
1147
- console.error(chalk8.red(` Error: ${result.error}`));
935
+ console.error(chalk6.red(` Error: ${result.error}`));
1148
936
  result.steps.forEach((step) => {
1149
937
  if (!step.passed) {
1150
- console.error(chalk8.red(` Step Failed: ${step.stepName}`));
938
+ console.error(chalk6.red(` Step Failed: ${step.stepName}`));
1151
939
  if (step.output) console.error(` Output:`, step.output);
1152
940
  if (step.error) console.error(` Error:`, step.error);
1153
941
  }
@@ -1158,24 +946,24 @@ var testCommand = new Command7("test").description("Run Quality Protocol test sc
1158
946
  }
1159
947
  }
1160
948
  } catch (e) {
1161
- console.error(chalk8.red(`Failed to load or run suite ${file}: ${e}`));
949
+ console.error(chalk6.red(`Failed to load or run suite ${file}: ${e}`));
1162
950
  totalFailed++;
1163
951
  }
1164
952
  }
1165
- console.log(chalk8.dim(`
953
+ console.log(chalk6.dim(`
1166
954
  -------------------------------------`));
1167
955
  if (totalFailed > 0) {
1168
- console.log(chalk8.red(`FAILED: ${totalFailed} scenarios failed. ${totalPassed} passed.`));
956
+ console.log(chalk6.red(`FAILED: ${totalFailed} scenarios failed. ${totalPassed} passed.`));
1169
957
  process.exit(1);
1170
958
  } else {
1171
- console.log(chalk8.green(`SUCCESS: All ${totalPassed} scenarios passed.`));
959
+ console.log(chalk6.green(`SUCCESS: All ${totalPassed} scenarios passed.`));
1172
960
  process.exit(0);
1173
961
  }
1174
962
  });
1175
963
 
1176
964
  // src/commands/validate.ts
1177
965
  import { Command as Command8 } from "commander";
1178
- import chalk9 from "chalk";
966
+ import chalk7 from "chalk";
1179
967
  import { ObjectStackDefinitionSchema as ObjectStackDefinitionSchema2 } from "@objectstack/spec";
1180
968
  var validateCommand = new Command8("validate").description("Validate ObjectStack configuration against the protocol schema").argument("[config]", "Configuration file path").option("--strict", "Treat warnings as errors").option("--json", "Output results as JSON").action(async (configPath, options) => {
1181
969
  const timer = createTimer();
@@ -1229,12 +1017,12 @@ var validateCommand = new Command8("validate").description("Validate ObjectStack
1229
1017
  warnings.push("Missing manifest.namespace \u2014 required for multi-app hosting");
1230
1018
  }
1231
1019
  console.log("");
1232
- printSuccess(`Validation passed ${chalk9.dim(`(${timer.display()})`)}`);
1020
+ printSuccess(`Validation passed ${chalk7.dim(`(${timer.display()})`)}`);
1233
1021
  console.log("");
1234
1022
  if (config.manifest) {
1235
- console.log(` ${chalk9.bold(config.manifest.name || config.manifest.id || "Unnamed")} ${chalk9.dim(`v${config.manifest.version || "0.0.0"}`)}`);
1023
+ console.log(` ${chalk7.bold(config.manifest.name || config.manifest.id || "Unnamed")} ${chalk7.dim(`v${config.manifest.version || "0.0.0"}`)}`);
1236
1024
  if (config.manifest.description) {
1237
- console.log(chalk9.dim(` ${config.manifest.description}`));
1025
+ console.log(chalk7.dim(` ${config.manifest.description}`));
1238
1026
  }
1239
1027
  console.log("");
1240
1028
  }
@@ -1242,7 +1030,7 @@ var validateCommand = new Command8("validate").description("Validate ObjectStack
1242
1030
  if (warnings.length > 0) {
1243
1031
  console.log("");
1244
1032
  for (const w of warnings) {
1245
- console.log(chalk9.yellow(` \u26A0 ${w}`));
1033
+ console.log(chalk7.yellow(` \u26A0 ${w}`));
1246
1034
  }
1247
1035
  if (options.strict) {
1248
1036
  console.log("");
@@ -1268,9 +1056,9 @@ var validateCommand = new Command8("validate").description("Validate ObjectStack
1268
1056
 
1269
1057
  // src/commands/init.ts
1270
1058
  import { Command as Command9 } from "commander";
1271
- import chalk10 from "chalk";
1272
- import fs9 from "fs";
1273
- import path9 from "path";
1059
+ import chalk8 from "chalk";
1060
+ import fs8 from "fs";
1061
+ import path8 from "path";
1274
1062
  var TEMPLATES = {
1275
1063
  app: {
1276
1064
  description: "Full application with objects, views, and actions",
@@ -1435,16 +1223,16 @@ function toTitleCase(str) {
1435
1223
  var initCommand = new Command9("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) => {
1436
1224
  printHeader("Init");
1437
1225
  const cwd = process.cwd();
1438
- const projectName = name || path9.basename(cwd);
1226
+ const projectName = name || path8.basename(cwd);
1439
1227
  const template = TEMPLATES[options.template];
1440
1228
  if (!template) {
1441
1229
  printError(`Unknown template: ${options.template}`);
1442
- console.log(chalk10.dim(` Available: ${Object.keys(TEMPLATES).join(", ")}`));
1230
+ console.log(chalk8.dim(` Available: ${Object.keys(TEMPLATES).join(", ")}`));
1443
1231
  process.exit(1);
1444
1232
  }
1445
- if (fs9.existsSync(path9.join(cwd, "objectstack.config.ts"))) {
1233
+ if (fs8.existsSync(path8.join(cwd, "objectstack.config.ts"))) {
1446
1234
  printError("objectstack.config.ts already exists in this directory");
1447
- console.log(chalk10.dim(" Use `objectstack generate` to add metadata to an existing project"));
1235
+ console.log(chalk8.dim(" Use `objectstack generate` to add metadata to an existing project"));
1448
1236
  process.exit(1);
1449
1237
  }
1450
1238
  printKV("Project", projectName);
@@ -1453,8 +1241,8 @@ var initCommand = new Command9("init").description("Initialize a new ObjectStack
1453
1241
  console.log("");
1454
1242
  const createdFiles = [];
1455
1243
  try {
1456
- const pkgPath = path9.join(cwd, "package.json");
1457
- if (!fs9.existsSync(pkgPath)) {
1244
+ const pkgPath = path8.join(cwd, "package.json");
1245
+ if (!fs8.existsSync(pkgPath)) {
1458
1246
  const pkg2 = {
1459
1247
  name: projectName,
1460
1248
  version: "0.1.0",
@@ -1464,16 +1252,16 @@ var initCommand = new Command9("init").description("Initialize a new ObjectStack
1464
1252
  dependencies: template.dependencies,
1465
1253
  devDependencies: template.devDependencies
1466
1254
  };
1467
- fs9.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n");
1255
+ fs8.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n");
1468
1256
  createdFiles.push("package.json");
1469
1257
  } else {
1470
1258
  printInfo("package.json already exists, skipping");
1471
1259
  }
1472
1260
  const configContent = template.configContent(projectName);
1473
- fs9.writeFileSync(path9.join(cwd, "objectstack.config.ts"), configContent);
1261
+ fs8.writeFileSync(path8.join(cwd, "objectstack.config.ts"), configContent);
1474
1262
  createdFiles.push("objectstack.config.ts");
1475
- const tsconfigPath = path9.join(cwd, "tsconfig.json");
1476
- if (!fs9.existsSync(tsconfigPath)) {
1263
+ const tsconfigPath = path8.join(cwd, "tsconfig.json");
1264
+ if (!fs8.existsSync(tsconfigPath)) {
1477
1265
  const tsconfig = {
1478
1266
  compilerOptions: {
1479
1267
  target: "ES2022",
@@ -1489,30 +1277,30 @@ var initCommand = new Command9("init").description("Initialize a new ObjectStack
1489
1277
  include: ["*.ts", "src/**/*"],
1490
1278
  exclude: ["dist", "node_modules"]
1491
1279
  };
1492
- fs9.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n");
1280
+ fs8.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n");
1493
1281
  createdFiles.push("tsconfig.json");
1494
1282
  }
1495
1283
  for (const [filePath, contentFn] of Object.entries(template.srcFiles)) {
1496
1284
  const resolvedPath = filePath.replace("__name__", projectName);
1497
- const fullPath = path9.join(cwd, resolvedPath);
1498
- const dir = path9.dirname(fullPath);
1499
- if (!fs9.existsSync(dir)) {
1500
- fs9.mkdirSync(dir, { recursive: true });
1285
+ const fullPath = path8.join(cwd, resolvedPath);
1286
+ const dir = path8.dirname(fullPath);
1287
+ if (!fs8.existsSync(dir)) {
1288
+ fs8.mkdirSync(dir, { recursive: true });
1501
1289
  }
1502
- fs9.writeFileSync(fullPath, contentFn(projectName));
1290
+ fs8.writeFileSync(fullPath, contentFn(projectName));
1503
1291
  createdFiles.push(resolvedPath);
1504
1292
  }
1505
- const gitignorePath = path9.join(cwd, ".gitignore");
1506
- if (!fs9.existsSync(gitignorePath)) {
1507
- fs9.writeFileSync(gitignorePath, `node_modules/
1293
+ const gitignorePath = path8.join(cwd, ".gitignore");
1294
+ if (!fs8.existsSync(gitignorePath)) {
1295
+ fs8.writeFileSync(gitignorePath, `node_modules/
1508
1296
  dist/
1509
1297
  *.tsbuildinfo
1510
1298
  `);
1511
1299
  createdFiles.push(".gitignore");
1512
1300
  }
1513
- console.log(chalk10.bold(" Created files:"));
1301
+ console.log(chalk8.bold(" Created files:"));
1514
1302
  for (const f of createdFiles) {
1515
- console.log(chalk10.green(` + ${f}`));
1303
+ console.log(chalk8.green(` + ${f}`));
1516
1304
  }
1517
1305
  console.log("");
1518
1306
  if (options.install !== false) {
@@ -1526,10 +1314,10 @@ dist/
1526
1314
  }
1527
1315
  printSuccess("Project initialized!");
1528
1316
  console.log("");
1529
- console.log(chalk10.bold(" Next steps:"));
1530
- console.log(chalk10.dim(" objectstack validate # Check configuration"));
1531
- console.log(chalk10.dim(" objectstack dev # Start development server"));
1532
- console.log(chalk10.dim(" objectstack generate # Add objects, views, etc."));
1317
+ console.log(chalk8.bold(" Next steps:"));
1318
+ console.log(chalk8.dim(" objectstack validate # Check configuration"));
1319
+ console.log(chalk8.dim(" objectstack dev # Start development server"));
1320
+ console.log(chalk8.dim(" objectstack generate # Add objects, views, etc."));
1533
1321
  console.log("");
1534
1322
  } catch (error) {
1535
1323
  printError(error.message || String(error));
@@ -1537,12 +1325,12 @@ dist/
1537
1325
  }
1538
1326
  });
1539
1327
  function printWarning2(msg) {
1540
- console.log(chalk10.yellow(` \u26A0 ${msg}`));
1328
+ console.log(chalk8.yellow(` \u26A0 ${msg}`));
1541
1329
  }
1542
1330
 
1543
1331
  // src/commands/info.ts
1544
1332
  import { Command as Command10 } from "commander";
1545
- import chalk11 from "chalk";
1333
+ import chalk9 from "chalk";
1546
1334
  var infoCommand = new Command10("info").description("Display metadata summary of an ObjectStack configuration").argument("[config]", "Configuration file path").option("--json", "Output as JSON").action(async (configPath, options) => {
1547
1335
  const timer = createTimer();
1548
1336
  if (!options.json) {
@@ -1568,9 +1356,9 @@ var infoCommand = new Command10("info").description("Display metadata summary of
1568
1356
  if (config.manifest) {
1569
1357
  const m = config.manifest;
1570
1358
  console.log("");
1571
- console.log(` ${chalk11.bold(m.name || m.id || "Unnamed")} ${chalk11.dim(`v${m.version || "0.0.0"}`)}`);
1572
- if (m.id) console.log(chalk11.dim(` ${m.id}`));
1573
- if (m.description) console.log(chalk11.dim(` ${m.description}`));
1359
+ console.log(` ${chalk9.bold(m.name || m.id || "Unnamed")} ${chalk9.dim(`v${m.version || "0.0.0"}`)}`);
1360
+ if (m.id) console.log(chalk9.dim(` ${m.id}`));
1361
+ if (m.description) console.log(chalk9.dim(` ${m.description}`));
1574
1362
  if (m.namespace) printKV(" Namespace", m.namespace);
1575
1363
  if (m.type) printKV(" Type", m.type);
1576
1364
  }
@@ -1578,35 +1366,35 @@ var infoCommand = new Command10("info").description("Display metadata summary of
1578
1366
  printMetadataStats(stats);
1579
1367
  if (config.objects && config.objects.length > 0) {
1580
1368
  console.log("");
1581
- console.log(chalk11.bold(" Objects:"));
1369
+ console.log(chalk9.bold(" Objects:"));
1582
1370
  for (const obj of config.objects) {
1583
1371
  const fieldCount = obj.fields ? Object.keys(obj.fields).length : 0;
1584
1372
  const ownership = obj.ownership || "own";
1585
1373
  console.log(
1586
- ` ${chalk11.cyan(obj.name || "?")}` + chalk11.dim(` (${fieldCount} fields, ${ownership})`) + (obj.label ? chalk11.dim(` \u2014 ${obj.label}`) : "")
1374
+ ` ${chalk9.cyan(obj.name || "?")}` + chalk9.dim(` (${fieldCount} fields, ${ownership})`) + (obj.label ? chalk9.dim(` \u2014 ${obj.label}`) : "")
1587
1375
  );
1588
1376
  }
1589
1377
  }
1590
1378
  if (config.agents && config.agents.length > 0) {
1591
1379
  console.log("");
1592
- console.log(chalk11.bold(" Agents:"));
1380
+ console.log(chalk9.bold(" Agents:"));
1593
1381
  for (const agent of config.agents) {
1594
1382
  console.log(
1595
- ` ${chalk11.magenta(agent.name || "?")}` + (agent.role ? chalk11.dim(` \u2014 ${agent.role}`) : "")
1383
+ ` ${chalk9.magenta(agent.name || "?")}` + (agent.role ? chalk9.dim(` \u2014 ${agent.role}`) : "")
1596
1384
  );
1597
1385
  }
1598
1386
  }
1599
1387
  if (config.apps && config.apps.length > 0) {
1600
1388
  console.log("");
1601
- console.log(chalk11.bold(" Apps:"));
1389
+ console.log(chalk9.bold(" Apps:"));
1602
1390
  for (const app of config.apps) {
1603
1391
  console.log(
1604
- ` ${chalk11.green(app.name || "?")}` + (app.label ? chalk11.dim(` \u2014 ${app.label}`) : "")
1392
+ ` ${chalk9.green(app.name || "?")}` + (app.label ? chalk9.dim(` \u2014 ${app.label}`) : "")
1605
1393
  );
1606
1394
  }
1607
1395
  }
1608
1396
  console.log("");
1609
- console.log(chalk11.dim(` Loaded in ${duration}ms`));
1397
+ console.log(chalk9.dim(` Loaded in ${duration}ms`));
1610
1398
  console.log("");
1611
1399
  } catch (error) {
1612
1400
  if (options.json) {
@@ -1621,9 +1409,9 @@ var infoCommand = new Command10("info").description("Display metadata summary of
1621
1409
 
1622
1410
  // src/commands/generate.ts
1623
1411
  import { Command as Command11 } from "commander";
1624
- import chalk12 from "chalk";
1625
- import fs10 from "fs";
1626
- import path10 from "path";
1412
+ import chalk10 from "chalk";
1413
+ import fs9 from "fs";
1414
+ import path9 from "path";
1627
1415
  var GENERATORS = {
1628
1416
  object: {
1629
1417
  description: "Business data object",
@@ -1804,75 +1592,543 @@ function toTitleCase2(str) {
1804
1592
  function toSnakeCase(str) {
1805
1593
  return str.replace(/[-]/g, "_").replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`).replace(/^_/, "");
1806
1594
  }
1807
- var generateCommand = new Command11("generate").alias("g").description("Generate metadata files (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) => {
1595
+ var FIELD_TYPE_MAP = {
1596
+ text: "string",
1597
+ textarea: "string",
1598
+ richtext: "string",
1599
+ html: "string",
1600
+ markdown: "string",
1601
+ number: "number",
1602
+ integer: "number",
1603
+ currency: "number",
1604
+ percent: "number",
1605
+ boolean: "boolean",
1606
+ date: "string",
1607
+ datetime: "string",
1608
+ time: "string",
1609
+ email: "string",
1610
+ phone: "string",
1611
+ url: "string",
1612
+ select: "string",
1613
+ multiselect: "string[]",
1614
+ lookup: "string",
1615
+ master_detail: "string",
1616
+ formula: "unknown",
1617
+ autonumber: "string",
1618
+ json: "Record<string, unknown>",
1619
+ file: "string",
1620
+ image: "string",
1621
+ password: "string",
1622
+ slug: "string",
1623
+ uuid: "string",
1624
+ ip_address: "string",
1625
+ color: "string",
1626
+ rating: "number",
1627
+ geo_point: "{ lat: number; lng: number }",
1628
+ vector: "number[]",
1629
+ encrypted: "string"
1630
+ };
1631
+ function fieldTypeToTs(fieldType, multiple) {
1632
+ const base = FIELD_TYPE_MAP[fieldType] || "unknown";
1633
+ return multiple ? `${base}[]` : base;
1634
+ }
1635
+ function generateTypesFromConfig(config) {
1636
+ const lines = [
1637
+ "// Auto-generated by ObjectStack CLI \u2014 do not edit manually",
1638
+ `// Generated at ${(/* @__PURE__ */ new Date()).toISOString()}`,
1639
+ "",
1640
+ "import type { Data } from '@objectstack/spec';",
1641
+ ""
1642
+ ];
1643
+ const objects = [];
1644
+ const rawObjects = config.objects ?? config.data?.objects ?? {};
1645
+ if (Array.isArray(rawObjects)) {
1646
+ objects.push(...rawObjects);
1647
+ } else if (typeof rawObjects === "object") {
1648
+ for (const val of Object.values(rawObjects)) {
1649
+ if (val && typeof val === "object") objects.push(val);
1650
+ }
1651
+ }
1652
+ if (objects.length === 0) {
1653
+ lines.push("// No objects found in configuration");
1654
+ return lines.join("\n") + "\n";
1655
+ }
1656
+ for (const obj of objects) {
1657
+ const name = String(obj.name || "unknown");
1658
+ const typeName = name.split("_").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
1659
+ const fields = obj.fields ?? {};
1660
+ lines.push(`/** ${String(obj.label || typeName)} record type */`);
1661
+ lines.push(`export interface ${typeName}Record {`);
1662
+ lines.push(" id: string;");
1663
+ for (const [fieldName, fieldDef] of Object.entries(fields)) {
1664
+ const fType = String(fieldDef.type || "text");
1665
+ const tsType = fieldTypeToTs(fType, !!fieldDef.multiple);
1666
+ const required = fieldDef.required ? "" : "?";
1667
+ if (fieldDef.label) {
1668
+ lines.push(` /** ${fieldDef.label} */`);
1669
+ }
1670
+ lines.push(` ${fieldName}${required}: ${tsType};`);
1671
+ }
1672
+ lines.push("}");
1673
+ lines.push("");
1674
+ }
1675
+ return lines.join("\n") + "\n";
1676
+ }
1677
+ var generateMetadataCommand = new Command11("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) => {
1808
1678
  printHeader("Generate");
1809
1679
  const generator = GENERATORS[type];
1810
1680
  if (!generator) {
1811
1681
  printError(`Unknown type: ${type}`);
1812
1682
  console.log("");
1813
- console.log(chalk12.bold(" Available types:"));
1683
+ console.log(chalk10.bold(" Available types:"));
1814
1684
  for (const [key, gen] of Object.entries(GENERATORS)) {
1815
- console.log(` ${chalk12.cyan(key.padEnd(12))} ${chalk12.dim(gen.description)}`);
1685
+ console.log(` ${chalk10.cyan(key.padEnd(12))} ${chalk10.dim(gen.description)}`);
1816
1686
  }
1817
1687
  console.log("");
1818
- console.log(chalk12.dim(" Usage: objectstack generate <type> <name>"));
1819
- console.log(chalk12.dim(" Example: objectstack generate object project"));
1820
- console.log(chalk12.dim(" Alias: os g object project"));
1688
+ console.log(chalk10.dim(" Usage: objectstack generate <type> <name>"));
1689
+ console.log(chalk10.dim(" Example: objectstack generate object project"));
1690
+ console.log(chalk10.dim(" Alias: os g object project"));
1821
1691
  process.exit(1);
1822
1692
  }
1823
1693
  const dir = options.dir || generator.defaultDir;
1824
1694
  const fileName = `${toSnakeCase(name)}.ts`;
1825
- const filePath = path10.join(process.cwd(), dir, fileName);
1826
- console.log(` ${chalk12.dim("Type:")} ${chalk12.cyan(type)} \u2014 ${generator.description}`);
1827
- console.log(` ${chalk12.dim("Name:")} ${chalk12.white(name)}`);
1828
- console.log(` ${chalk12.dim("File:")} ${chalk12.white(path10.join(dir, fileName))}`);
1695
+ const filePath = path9.join(process.cwd(), dir, fileName);
1696
+ console.log(` ${chalk10.dim("Type:")} ${chalk10.cyan(type)} \u2014 ${generator.description}`);
1697
+ console.log(` ${chalk10.dim("Name:")} ${chalk10.white(name)}`);
1698
+ console.log(` ${chalk10.dim("File:")} ${chalk10.white(path9.join(dir, fileName))}`);
1829
1699
  console.log("");
1830
1700
  if (options.dryRun) {
1831
1701
  printInfo("Dry run \u2014 no files written");
1832
1702
  console.log("");
1833
- console.log(chalk12.dim(" Content:"));
1834
- console.log(chalk12.dim(" " + "-".repeat(38)));
1703
+ console.log(chalk10.dim(" Content:"));
1704
+ console.log(chalk10.dim(" " + "-".repeat(38)));
1835
1705
  const content = generator.generate(name);
1836
1706
  for (const line of content.split("\n")) {
1837
- console.log(chalk12.dim(` ${line}`));
1707
+ console.log(chalk10.dim(` ${line}`));
1838
1708
  }
1839
1709
  console.log("");
1840
1710
  return;
1841
1711
  }
1842
- if (fs10.existsSync(filePath)) {
1712
+ if (fs9.existsSync(filePath)) {
1843
1713
  printError(`File already exists: ${filePath}`);
1844
1714
  process.exit(1);
1845
1715
  }
1846
1716
  try {
1847
- const fullDir = path10.dirname(filePath);
1848
- if (!fs10.existsSync(fullDir)) {
1849
- fs10.mkdirSync(fullDir, { recursive: true });
1717
+ const fullDir = path9.dirname(filePath);
1718
+ if (!fs9.existsSync(fullDir)) {
1719
+ fs9.mkdirSync(fullDir, { recursive: true });
1850
1720
  }
1851
1721
  const content = generator.generate(name);
1852
- fs10.writeFileSync(filePath, content);
1853
- printSuccess(`Created ${path10.join(dir, fileName)}`);
1854
- const indexPath = path10.join(process.cwd(), dir, "index.ts");
1855
- if (fs10.existsSync(indexPath)) {
1856
- const indexContent = fs10.readFileSync(indexPath, "utf-8");
1722
+ fs9.writeFileSync(filePath, content);
1723
+ printSuccess(`Created ${path9.join(dir, fileName)}`);
1724
+ const indexPath = path9.join(process.cwd(), dir, "index.ts");
1725
+ if (fs9.existsSync(indexPath)) {
1726
+ const indexContent = fs9.readFileSync(indexPath, "utf-8");
1857
1727
  const exportLine = `export { default as ${toCamelCase3(name)} } from './${toSnakeCase(name)}';`;
1858
1728
  if (!indexContent.includes(toCamelCase3(name))) {
1859
- fs10.appendFileSync(indexPath, exportLine + "\n");
1729
+ fs9.appendFileSync(indexPath, exportLine + "\n");
1860
1730
  printSuccess(`Updated ${dir}/index.ts with export`);
1861
1731
  }
1862
1732
  } else {
1863
1733
  const exportLine = `export { default as ${toCamelCase3(name)} } from './${toSnakeCase(name)}';
1864
1734
  `;
1865
- fs10.writeFileSync(indexPath, exportLine);
1735
+ fs9.writeFileSync(indexPath, exportLine);
1866
1736
  printSuccess(`Created ${dir}/index.ts`);
1867
1737
  }
1868
1738
  console.log("");
1869
- console.log(chalk12.dim(` Tip: Run \`objectstack validate\` to check your config`));
1739
+ console.log(chalk10.dim(` Tip: Run \`objectstack validate\` to check your config`));
1740
+ console.log("");
1741
+ } catch (error) {
1742
+ printError(error.message || String(error));
1743
+ process.exit(1);
1744
+ }
1745
+ });
1746
+ var generateTypesCommand = new Command11("types").description("Generate TypeScript type definitions from ObjectStack configuration").argument("[config]", "Configuration file path").option("-o, --output <file>", "Output file path", "src/types/objectstack.d.ts").option("--dry-run", "Show what would be generated without writing files").action(async (configPath, options) => {
1747
+ printHeader("Generate Types");
1748
+ try {
1749
+ const { loadConfig: loadConfig2 } = await import("./config-A7BN6UIT.js");
1750
+ printInfo("Loading configuration...");
1751
+ const { config, absolutePath } = await loadConfig2(configPath);
1752
+ console.log(` ${chalk10.dim("Config:")} ${chalk10.white(absolutePath)}`);
1753
+ console.log(` ${chalk10.dim("Output:")} ${chalk10.white(options.output)}`);
1754
+ console.log("");
1755
+ const content = generateTypesFromConfig(config);
1756
+ if (options.dryRun) {
1757
+ printInfo("Dry run \u2014 no files written");
1758
+ console.log("");
1759
+ for (const line of content.split("\n")) {
1760
+ console.log(chalk10.dim(` ${line}`));
1761
+ }
1762
+ console.log("");
1763
+ return;
1764
+ }
1765
+ const outPath = path9.resolve(process.cwd(), options.output);
1766
+ const outDir = path9.dirname(outPath);
1767
+ if (!fs9.existsSync(outDir)) {
1768
+ fs9.mkdirSync(outDir, { recursive: true });
1769
+ }
1770
+ fs9.writeFileSync(outPath, content);
1771
+ printSuccess(`Generated types at ${options.output}`);
1772
+ console.log("");
1773
+ } catch (error) {
1774
+ printError(error.message || String(error));
1775
+ process.exit(1);
1776
+ }
1777
+ });
1778
+ var generateCommand = new Command11("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) => {
1779
+ if (!type) {
1780
+ printHeader("Generate");
1781
+ console.log(chalk10.bold(" Sub-commands:"));
1782
+ console.log(` ${chalk10.cyan("types".padEnd(12))} Generate TypeScript type definitions from config`);
1783
+ console.log("");
1784
+ console.log(chalk10.bold(" Metadata types:"));
1785
+ for (const [key, gen] of Object.entries(GENERATORS)) {
1786
+ console.log(` ${chalk10.cyan(key.padEnd(12))} ${chalk10.dim(gen.description)}`);
1787
+ }
1788
+ console.log("");
1789
+ console.log(chalk10.dim(" Usage: objectstack generate <type> <name>"));
1790
+ console.log(chalk10.dim(" Usage: objectstack generate types [config]"));
1791
+ return;
1792
+ }
1793
+ if (!name) {
1794
+ printError("Missing required argument: <name>");
1795
+ console.log(chalk10.dim(" Usage: objectstack generate <type> <name>"));
1796
+ process.exit(1);
1797
+ }
1798
+ await generateMetadataCommand.parseAsync([type, name, ...process.argv.slice(4)], { from: "user" });
1799
+ });
1800
+
1801
+ // src/commands/plugin.ts
1802
+ import { Command as Command12 } from "commander";
1803
+ import chalk11 from "chalk";
1804
+ import fs10 from "fs";
1805
+ import path10 from "path";
1806
+ function resolvePluginName(plugin) {
1807
+ if (typeof plugin === "string") return plugin;
1808
+ if (plugin && typeof plugin === "object") {
1809
+ const p = plugin;
1810
+ if (typeof p.name === "string") return p.name;
1811
+ if (p.constructor && p.constructor.name !== "Object") return p.constructor.name;
1812
+ }
1813
+ return "unknown";
1814
+ }
1815
+ function resolvePluginVersion(plugin) {
1816
+ if (plugin && typeof plugin === "object") {
1817
+ const p = plugin;
1818
+ if (typeof p.version === "string") return p.version;
1819
+ }
1820
+ return "-";
1821
+ }
1822
+ function resolvePluginType(plugin) {
1823
+ if (plugin && typeof plugin === "object") {
1824
+ const p = plugin;
1825
+ if (typeof p.type === "string") return p.type;
1826
+ }
1827
+ return "standard";
1828
+ }
1829
+ function readConfigText(configPath) {
1830
+ return fs10.readFileSync(configPath, "utf-8");
1831
+ }
1832
+ function addPluginToConfig(configPath, packageName) {
1833
+ let content = readConfigText(configPath);
1834
+ const shortName = packageName.replace(/^@[^/]+\//, "").replace(/^plugin-/, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
1835
+ const varName = shortName.replace(/-([a-z])/g, (_, c) => c.toUpperCase()) + "Plugin";
1836
+ const importLine = `import ${varName} from '${packageName}';
1837
+ `;
1838
+ if (content.includes(packageName)) {
1839
+ throw new Error(`Plugin '${packageName}' is already referenced in the config`);
1840
+ }
1841
+ const importRegex = /^import .+$/gm;
1842
+ let lastImportEnd = 0;
1843
+ let match;
1844
+ while ((match = importRegex.exec(content)) !== null) {
1845
+ lastImportEnd = match.index + match[0].length;
1846
+ }
1847
+ if (lastImportEnd > 0) {
1848
+ content = content.slice(0, lastImportEnd) + "\n" + importLine + content.slice(lastImportEnd);
1849
+ } else {
1850
+ content = importLine + "\n" + content;
1851
+ }
1852
+ if (/plugins\s*:\s*\[/.test(content)) {
1853
+ let replaced = false;
1854
+ content = content.replace(
1855
+ /(plugins\s*:\s*\[)/,
1856
+ (match2) => {
1857
+ if (replaced) return match2;
1858
+ replaced = true;
1859
+ return `${match2}
1860
+ ${varName},`;
1861
+ }
1862
+ );
1863
+ } else {
1864
+ content = content.replace(
1865
+ /(defineStack\(\{[\s\S]*?)(}\s*\))/,
1866
+ `$1 plugins: [
1867
+ ${varName},
1868
+ ],
1869
+ $2`
1870
+ );
1871
+ }
1872
+ fs10.writeFileSync(configPath, content);
1873
+ }
1874
+ function removePluginFromConfig(configPath, pluginName) {
1875
+ let content = readConfigText(configPath);
1876
+ const importRegex = new RegExp(`^import .+['"]${escapeRegex(pluginName)}['"]\\s*;?\\s*$\\n?`, "gm");
1877
+ const hadImport = importRegex.test(content);
1878
+ importRegex.lastIndex = 0;
1879
+ content = content.replace(importRegex, "");
1880
+ const shortName = pluginName.replace(/^@[^/]+\//, "").replace(/^plugin-/, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
1881
+ const varName = shortName.replace(/-([a-z])/g, (_, c) => c.toUpperCase()) + "Plugin";
1882
+ if (!hadImport) {
1883
+ const varImportRegex = new RegExp(`^import .* ${escapeRegex(varName)} .+$\\n?`, "gm");
1884
+ content = content.replace(varImportRegex, "");
1885
+ }
1886
+ const entryPatterns = [
1887
+ new RegExp(`\\s*${escapeRegex(varName)},?\\n?`, "g"),
1888
+ new RegExp(`\\s*['"]${escapeRegex(pluginName)}['"],?\\n?`, "g")
1889
+ ];
1890
+ for (const pattern of entryPatterns) {
1891
+ content = content.replace(pattern, "\n");
1892
+ }
1893
+ content = content.replace(/plugins\s*:\s*\[\s*\],?\n?/g, "");
1894
+ fs10.writeFileSync(configPath, content);
1895
+ }
1896
+ function escapeRegex(str) {
1897
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1898
+ }
1899
+ var listCommand = new Command12("list").alias("ls").description("List plugins defined in the configuration").argument("[config]", "Configuration file path").option("--json", "Output as JSON").action(async (configSource, options) => {
1900
+ try {
1901
+ const { config } = await loadConfig(configSource);
1902
+ const plugins = config.plugins || [];
1903
+ const devPlugins = config.devPlugins || [];
1904
+ if (options?.json) {
1905
+ const data = {
1906
+ plugins: plugins.map((p) => ({
1907
+ name: resolvePluginName(p),
1908
+ version: resolvePluginVersion(p),
1909
+ type: resolvePluginType(p),
1910
+ dev: false
1911
+ })),
1912
+ devPlugins: devPlugins.map((p) => ({
1913
+ name: resolvePluginName(p),
1914
+ version: resolvePluginVersion(p),
1915
+ type: resolvePluginType(p),
1916
+ dev: true
1917
+ }))
1918
+ };
1919
+ console.log(JSON.stringify(data, null, 2));
1920
+ return;
1921
+ }
1922
+ printHeader("Plugins");
1923
+ if (plugins.length === 0 && devPlugins.length === 0) {
1924
+ printInfo("No plugins configured");
1925
+ console.log("");
1926
+ console.log(chalk11.dim(" Hint: Add plugins to your objectstack.config.ts"));
1927
+ console.log(chalk11.dim(" Or run: os plugin add <package-name>"));
1928
+ console.log("");
1929
+ return;
1930
+ }
1931
+ if (plugins.length > 0) {
1932
+ console.log(chalk11.bold(`
1933
+ Plugins (${plugins.length}):`));
1934
+ for (const plugin of plugins) {
1935
+ const name = resolvePluginName(plugin);
1936
+ const version = resolvePluginVersion(plugin);
1937
+ const type = resolvePluginType(plugin);
1938
+ console.log(
1939
+ ` ${chalk11.cyan("\u25CF")} ${chalk11.white(name)}` + (version !== "-" ? chalk11.dim(` v${version}`) : "") + (type !== "standard" ? chalk11.dim(` [${type}]`) : "")
1940
+ );
1941
+ }
1942
+ }
1943
+ if (devPlugins.length > 0) {
1944
+ console.log(chalk11.bold(`
1945
+ Dev Plugins (${devPlugins.length}):`));
1946
+ for (const plugin of devPlugins) {
1947
+ const name = resolvePluginName(plugin);
1948
+ const version = resolvePluginVersion(plugin);
1949
+ console.log(
1950
+ ` ${chalk11.yellow("\u25CF")} ${chalk11.white(name)}` + (version !== "-" ? chalk11.dim(` v${version}`) : "") + chalk11.dim(" [dev]")
1951
+ );
1952
+ }
1953
+ }
1954
+ console.log("");
1955
+ } catch (error) {
1956
+ printError(error.message || String(error));
1957
+ process.exit(1);
1958
+ }
1959
+ });
1960
+ var infoSubCommand = new Command12("info").description("Show detailed information about a plugin").argument("<name>", "Plugin name or package name").argument("[config]", "Configuration file path").action(async (name, configSource) => {
1961
+ try {
1962
+ const { config } = await loadConfig(configSource);
1963
+ const allPlugins = [
1964
+ ...config.plugins || [],
1965
+ ...config.devPlugins || []
1966
+ ];
1967
+ const found = allPlugins.find((p) => {
1968
+ const pName = resolvePluginName(p);
1969
+ return pName === name || pName.includes(name);
1970
+ });
1971
+ if (!found) {
1972
+ printError(`Plugin '${name}' not found in configuration`);
1973
+ console.log("");
1974
+ console.log(chalk11.dim(" Available plugins:"));
1975
+ for (const p of allPlugins) {
1976
+ console.log(chalk11.dim(` - ${resolvePluginName(p)}`));
1977
+ }
1978
+ console.log("");
1979
+ process.exit(1);
1980
+ }
1981
+ printHeader(`Plugin: ${resolvePluginName(found)}`);
1982
+ printKV("Name", resolvePluginName(found));
1983
+ printKV("Version", resolvePluginVersion(found));
1984
+ printKV("Type", resolvePluginType(found));
1985
+ const isDev = (config.devPlugins || []).includes(found);
1986
+ printKV("Environment", isDev ? "development" : "production");
1987
+ if (found && typeof found === "object") {
1988
+ const p = found;
1989
+ if (typeof p.description === "string") {
1990
+ printKV("Description", p.description);
1991
+ }
1992
+ if (Array.isArray(p.dependencies) && p.dependencies.length > 0) {
1993
+ printKV("Dependencies", p.dependencies.join(", "));
1994
+ }
1995
+ if (typeof p.init === "function") {
1996
+ printInfo("This is a runtime plugin instance (has init function)");
1997
+ }
1998
+ }
1999
+ if (typeof found === "string") {
2000
+ printInfo("This is a string reference (will be imported at runtime)");
2001
+ }
2002
+ console.log("");
2003
+ } catch (error) {
2004
+ printError(error.message || String(error));
2005
+ process.exit(1);
2006
+ }
2007
+ });
2008
+ var addCommand = new Command12("add").description("Add a plugin to objectstack.config.ts").argument("<package>", "Plugin package name (e.g. @objectstack/plugin-auth)").option("-d, --dev", "Add as a dev-only plugin").option("-c, --config <path>", "Configuration file path").action(async (packageName, options) => {
2009
+ try {
2010
+ const configPath = resolveConfigPath(options?.config);
2011
+ printHeader("Add Plugin");
2012
+ console.log(` ${chalk11.dim("Package:")} ${chalk11.white(packageName)}`);
2013
+ console.log(` ${chalk11.dim("Config:")} ${chalk11.white(path10.relative(process.cwd(), configPath))}`);
2014
+ console.log("");
2015
+ addPluginToConfig(configPath, packageName);
2016
+ printSuccess(`Added ${chalk11.cyan(packageName)} to config`);
2017
+ console.log("");
2018
+ console.log(chalk11.dim(" Next steps:"));
2019
+ console.log(chalk11.dim(` 1. Install the package: pnpm add ${packageName}`));
2020
+ console.log(chalk11.dim(" 2. Run: os validate"));
2021
+ console.log("");
2022
+ } catch (error) {
2023
+ printError(error.message || String(error));
2024
+ process.exit(1);
2025
+ }
2026
+ });
2027
+ var removeCommand = new Command12("remove").alias("rm").description("Remove a plugin from objectstack.config.ts").argument("<name>", "Plugin name or package name to remove").option("-c, --config <path>", "Configuration file path").action(async (pluginName, options) => {
2028
+ try {
2029
+ const configPath = resolveConfigPath(options?.config);
2030
+ printHeader("Remove Plugin");
2031
+ console.log(` ${chalk11.dim("Plugin:")} ${chalk11.white(pluginName)}`);
2032
+ console.log(` ${chalk11.dim("Config:")} ${chalk11.white(path10.relative(process.cwd(), configPath))}`);
2033
+ console.log("");
2034
+ removePluginFromConfig(configPath, pluginName);
2035
+ printSuccess(`Removed ${chalk11.cyan(pluginName)} from config`);
2036
+ console.log("");
2037
+ console.log(chalk11.dim(" Tip: Run `pnpm remove " + pluginName + "` to uninstall the package"));
1870
2038
  console.log("");
1871
2039
  } catch (error) {
1872
2040
  printError(error.message || String(error));
1873
2041
  process.exit(1);
1874
2042
  }
1875
2043
  });
2044
+ var pluginCommand = new Command12("plugin").description("Manage plugins (list, info, add, remove)").addCommand(listCommand).addCommand(infoSubCommand).addCommand(addCommand).addCommand(removeCommand);
2045
+
2046
+ // src/utils/plugin-commands.ts
2047
+ import chalk12 from "chalk";
2048
+ async function loadPluginCommands(program2) {
2049
+ let config;
2050
+ try {
2051
+ const loaded = await loadConfig();
2052
+ config = loaded.config;
2053
+ } catch {
2054
+ return;
2055
+ }
2056
+ const plugins = [
2057
+ ...config.plugins || [],
2058
+ ...config.devPlugins || []
2059
+ ];
2060
+ const contributions = [];
2061
+ for (const plugin of plugins) {
2062
+ if (!plugin || typeof plugin !== "object") continue;
2063
+ const p = plugin;
2064
+ const manifest = p.manifest;
2065
+ const contributes = manifest?.contributes ?? p.contributes;
2066
+ if (!contributes) continue;
2067
+ const commands = contributes.commands;
2068
+ if (!Array.isArray(commands)) continue;
2069
+ const pluginName = resolvePluginName2(p);
2070
+ for (const cmd of commands) {
2071
+ if (!cmd || typeof cmd.name !== "string") continue;
2072
+ contributions.push({
2073
+ name: cmd.name,
2074
+ description: typeof cmd.description === "string" ? cmd.description : void 0,
2075
+ module: typeof cmd.module === "string" ? cmd.module : void 0,
2076
+ pluginName
2077
+ });
2078
+ }
2079
+ }
2080
+ if (contributions.length === 0) return;
2081
+ for (const contribution of contributions) {
2082
+ try {
2083
+ const commands = await importPluginCommands(contribution);
2084
+ for (const cmd of commands) {
2085
+ program2.addCommand(cmd);
2086
+ }
2087
+ } catch (error) {
2088
+ if (process.env.DEBUG) {
2089
+ const message = error instanceof Error ? error.message : String(error);
2090
+ console.error(
2091
+ chalk12.yellow(` \u26A0 Failed to load CLI command '${contribution.name}' from plugin '${contribution.pluginName}': ${message}`)
2092
+ );
2093
+ }
2094
+ }
2095
+ }
2096
+ }
2097
+ async function importPluginCommands(contribution) {
2098
+ const moduleId = contribution.module ? `${contribution.pluginName}/${contribution.module.replace(/^\.\//, "")}` : contribution.pluginName;
2099
+ const mod = await import(moduleId);
2100
+ if (Array.isArray(mod.commands)) {
2101
+ return mod.commands.filter(isCommandInstance);
2102
+ }
2103
+ const defaultExport = mod.default;
2104
+ if (defaultExport) {
2105
+ if (Array.isArray(defaultExport)) {
2106
+ return defaultExport.filter(isCommandInstance);
2107
+ }
2108
+ if (isCommandInstance(defaultExport)) {
2109
+ return [defaultExport];
2110
+ }
2111
+ }
2112
+ const commands = [];
2113
+ for (const key of Object.keys(mod)) {
2114
+ if (isCommandInstance(mod[key])) {
2115
+ commands.push(mod[key]);
2116
+ }
2117
+ }
2118
+ return commands;
2119
+ }
2120
+ function isCommandInstance(value) {
2121
+ if (value === null || typeof value !== "object") return false;
2122
+ const obj = value;
2123
+ return typeof obj.name === "function" && typeof obj.description === "function" && typeof obj.action === "function" && typeof obj.parse === "function";
2124
+ }
2125
+ function resolvePluginName2(plugin) {
2126
+ if (typeof plugin.name === "string") return plugin.name;
2127
+ const manifest = plugin.manifest;
2128
+ if (manifest && typeof manifest.name === "string") return manifest.name;
2129
+ if (plugin.constructor && plugin.constructor.name !== "Object") return plugin.constructor.name;
2130
+ return "unknown";
2131
+ }
1876
2132
 
1877
2133
  // src/bin.ts
1878
2134
  var require2 = createRequire2(import.meta.url);
@@ -1885,7 +2141,7 @@ process.on("unhandledRejection", (err) => {
1885
2141
  }
1886
2142
  process.exit(1);
1887
2143
  });
1888
- var program = new Command12();
2144
+ var program = new Command13();
1889
2145
  program.name("objectstack").description("ObjectStack CLI \u2014 Build metadata-driven apps with the ObjectStack Protocol").version(pkg.version, "-v, --version").configureHelp({
1890
2146
  sortSubcommands: false
1891
2147
  }).addHelpText("before", `
@@ -1894,6 +2150,7 @@ ${chalk13.bold.cyan("\u25C6 ObjectStack CLI")} ${chalk13.dim(`v${pkg.version}`)}
1894
2150
  ${chalk13.bold("Workflow:")}
1895
2151
  ${chalk13.dim("$")} os init ${chalk13.dim("# Create a new project")}
1896
2152
  ${chalk13.dim("$")} os generate object task ${chalk13.dim("# Add metadata")}
2153
+ ${chalk13.dim("$")} os plugin add <package> ${chalk13.dim("# Add a plugin")}
1897
2154
  ${chalk13.dim("$")} os validate ${chalk13.dim("# Check configuration")}
1898
2155
  ${chalk13.dim("$")} os dev ${chalk13.dim("# Start dev server")}
1899
2156
  ${chalk13.dim("$")} os studio ${chalk13.dim("# Dev server + Studio UI")}
@@ -1911,6 +2168,15 @@ program.addCommand(validateCommand);
1911
2168
  program.addCommand(infoCommand);
1912
2169
  program.addCommand(generateCommand);
1913
2170
  program.addCommand(createCommand);
2171
+ program.addCommand(pluginCommand);
1914
2172
  program.addCommand(testCommand);
1915
2173
  program.addCommand(doctorCommand);
1916
- program.parse(process.argv);
2174
+ loadPluginCommands(program).then(() => {
2175
+ program.parse(process.argv);
2176
+ }).catch((err) => {
2177
+ if (process.env.DEBUG) {
2178
+ console.error(chalk13.yellow(`
2179
+ \u26A0 Plugin command loading failed: ${err?.message || err}`));
2180
+ }
2181
+ program.parse(process.argv);
2182
+ });