@eventcatalog/cli 0.3.1 → 0.3.2

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/cli/index.js CHANGED
@@ -25,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli/index.ts
27
27
  var import_commander = require("commander");
28
- var import_node_fs3 = require("fs");
29
- var import_node_path2 = require("path");
28
+ var import_node_fs4 = require("fs");
29
+ var import_node_path3 = require("path");
30
30
 
31
31
  // src/cli/executor.ts
32
32
  var import_node_fs = require("fs");
@@ -352,11 +352,568 @@ ${vizBlock}` : grouped;
352
352
  return lines.join("\n");
353
353
  }
354
354
 
355
+ // src/cli/import.ts
356
+ var import_node_fs3 = require("fs");
357
+ var import_node_path2 = require("path");
358
+ var import_node_crypto = require("crypto");
359
+ var import_node_readline = require("readline");
360
+ var import_gray_matter = __toESM(require("gray-matter"));
361
+ var import_sdk4 = __toESM(require("@eventcatalog/sdk"));
362
+ var RESOURCE_TYPE_FROM_FOLDER = {
363
+ events: "event",
364
+ commands: "command",
365
+ queries: "query",
366
+ services: "service",
367
+ domains: "domain",
368
+ channels: "channel",
369
+ flows: "flow",
370
+ containers: "container",
371
+ "data-products": "dataProduct",
372
+ diagrams: "diagram",
373
+ users: "user",
374
+ teams: "team"
375
+ };
376
+ async function parseDSL(source, options) {
377
+ const { createEcServices, compile } = await import("@eventcatalog/language-server");
378
+ const { EmptyFileSystem, URI } = await import("langium");
379
+ const services = createEcServices(EmptyFileSystem);
380
+ const uri = URI.parse(`file:///import-${Date.now()}.ec`);
381
+ const document = services.shared.workspace.LangiumDocumentFactory.fromString(source, uri);
382
+ services.shared.workspace.LangiumDocuments.addDocument(document);
383
+ await services.shared.workspace.DocumentBuilder.build([document]);
384
+ const parserErrors = document.parseResult.parserErrors;
385
+ if (parserErrors.length > 0) {
386
+ const messages = parserErrors.map((e) => ` Line ${e.token?.startLine ?? "?"}: ${e.message}`);
387
+ throw new Error(`Parse errors:
388
+ ${messages.join("\n")}`);
389
+ }
390
+ const program2 = document.parseResult.value;
391
+ const outputs = compile(program2, { nested: options?.nested });
392
+ try {
393
+ services.shared.workspace.LangiumDocuments.deleteDocument(uri);
394
+ } catch {
395
+ }
396
+ return outputs;
397
+ }
398
+ function extractResourceTypeFolder(path) {
399
+ const segments = path.split("/");
400
+ let lastTypeFolder = segments[0];
401
+ for (const seg of segments) {
402
+ if (RESOURCE_TYPE_FROM_FOLDER[seg]) {
403
+ lastTypeFolder = seg;
404
+ }
405
+ }
406
+ return lastTypeFolder;
407
+ }
408
+ function parseCompiledOutput(output) {
409
+ const { data: frontmatter, content: markdown } = (0, import_gray_matter.default)(output.content);
410
+ const typeFolder = extractResourceTypeFolder(output.path);
411
+ const type = RESOURCE_TYPE_FROM_FOLDER[typeFolder] || typeFolder;
412
+ return {
413
+ type,
414
+ id: frontmatter.id,
415
+ version: frontmatter.version,
416
+ frontmatter,
417
+ markdown: markdown.trim(),
418
+ path: output.path
419
+ };
420
+ }
421
+ var MESSAGE_TYPE_FOLDER = {
422
+ event: "events",
423
+ command: "commands",
424
+ query: "queries",
425
+ channel: "channels"
426
+ };
427
+ var DEFAULT_STUB_VERSION = "0.0.1";
428
+ async function extractMessageStubs(source, compiledIds, nested = false) {
429
+ const { createEcServices } = await import("@eventcatalog/language-server");
430
+ const { EmptyFileSystem, URI } = await import("langium");
431
+ const services = createEcServices(EmptyFileSystem);
432
+ const uri = URI.parse(`file:///stub-extract-${Date.now()}.ec`);
433
+ const document = services.shared.workspace.LangiumDocumentFactory.fromString(source, uri);
434
+ services.shared.workspace.LangiumDocuments.addDocument(document);
435
+ await services.shared.workspace.DocumentBuilder.build([document]);
436
+ const program2 = document.parseResult.value;
437
+ const stubs = [];
438
+ const stubIds = /* @__PURE__ */ new Set();
439
+ function processDefinitions(definitions, parentPath = "") {
440
+ for (const def of definitions) {
441
+ if (def.$type === "VisualizerDef" && def.body) {
442
+ processDefinitions(def.body, parentPath);
443
+ continue;
444
+ }
445
+ if (def.$type === "DomainDef") {
446
+ const domainPath = nested ? `domains/${def.name}` : "";
447
+ const domainBody = def.body || [];
448
+ const domainServices = domainBody.filter((d) => d.$type === "ServiceDef");
449
+ processDefinitions(domainServices, domainPath);
450
+ const subdomains = domainBody.filter((d) => d.$type === "SubdomainDef");
451
+ for (const sub of subdomains) {
452
+ const subPath = nested ? `domains/${def.name}/subdomains/${sub.name}` : "";
453
+ const subServices = (sub.body || []).filter((d) => d.$type === "ServiceDef");
454
+ processDefinitions(subServices, subPath);
455
+ }
456
+ continue;
457
+ }
458
+ if (def.$type !== "ServiceDef") continue;
459
+ const servicePath = nested ? parentPath ? `${parentPath}/services/${def.name}` : `services/${def.name}` : "";
460
+ const body = def.body || [];
461
+ for (const stmt of body) {
462
+ if (stmt.$type !== "SendsStmt" && stmt.$type !== "ReceivesStmt") continue;
463
+ const msgType = stmt.messageType;
464
+ const msgName = stmt.messageName;
465
+ const hasBody = stmt.body && stmt.body.length > 0;
466
+ if (hasBody) continue;
467
+ const key = `${msgType}:${msgName}`;
468
+ if (compiledIds.has(key) || stubIds.has(key)) continue;
469
+ const folder = MESSAGE_TYPE_FOLDER[msgType];
470
+ if (!folder) continue;
471
+ const version2 = stmt.version || DEFAULT_STUB_VERSION;
472
+ const stubFolder = nested && servicePath ? `${servicePath}/${folder}` : folder;
473
+ stubIds.add(key);
474
+ stubs.push({
475
+ type: msgType,
476
+ id: msgName,
477
+ version: version2,
478
+ frontmatter: {
479
+ id: msgName,
480
+ name: msgName,
481
+ version: version2
482
+ },
483
+ markdown: "",
484
+ path: `${stubFolder}/${msgName}/versioned/${version2}/index.md`
485
+ });
486
+ if (stmt.channelClause) {
487
+ const channels = stmt.channelClause.channels || [];
488
+ for (const ch of channels) {
489
+ const chName = ch.channelName;
490
+ const chKey = `channel:${chName}`;
491
+ if (compiledIds.has(chKey) || stubIds.has(chKey)) continue;
492
+ const chVersion = ch.channelVersion || DEFAULT_STUB_VERSION;
493
+ const chFolder = nested && parentPath ? `${parentPath}/channels` : "channels";
494
+ stubIds.add(chKey);
495
+ stubs.push({
496
+ type: "channel",
497
+ id: chName,
498
+ version: chVersion,
499
+ frontmatter: {
500
+ id: chName,
501
+ name: chName,
502
+ version: chVersion
503
+ },
504
+ markdown: "",
505
+ path: `${chFolder}/${chName}/versioned/${chVersion}/index.md`
506
+ });
507
+ }
508
+ }
509
+ }
510
+ }
511
+ }
512
+ processDefinitions(program2.definitions);
513
+ try {
514
+ services.shared.workspace.LangiumDocuments.deleteDocument(uri);
515
+ } catch {
516
+ }
517
+ return stubs;
518
+ }
519
+ var SDK_WRITER_BASE = {
520
+ event: "events",
521
+ command: "commands",
522
+ query: "queries",
523
+ service: "services",
524
+ domain: "domains",
525
+ channel: "channels",
526
+ container: "containers",
527
+ team: "teams",
528
+ user: "users"
529
+ };
530
+ function extractSdkPath(compiledPath, resourceType) {
531
+ const dirPath = compiledPath.replace(/\/versioned\/[^/]+\/index\.md$/, "").replace(/\/index\.md$/, "").replace(/\.md$/, "");
532
+ const baseFolder = SDK_WRITER_BASE[resourceType];
533
+ if (!baseFolder) return "";
534
+ if (dirPath.startsWith(`${baseFolder}/`)) {
535
+ const relative = dirPath.slice(baseFolder.length + 1);
536
+ if (!relative.includes("/")) return "";
537
+ return relative;
538
+ }
539
+ return `../${dirPath}`;
540
+ }
541
+ var TYPES_WITH_NODE_GRAPH = /* @__PURE__ */ new Set(["event", "command", "query", "service", "domain", "channel", "flow"]);
542
+ function getWriter(sdk, type) {
543
+ switch (type) {
544
+ case "event":
545
+ return sdk.writeEvent;
546
+ case "command":
547
+ return sdk.writeCommand;
548
+ case "query":
549
+ return sdk.writeQuery;
550
+ case "service":
551
+ return sdk.writeService;
552
+ case "domain":
553
+ return sdk.writeDomain;
554
+ case "channel":
555
+ return sdk.writeChannel;
556
+ case "team":
557
+ return sdk.writeTeam;
558
+ case "user":
559
+ return sdk.writeUser;
560
+ default:
561
+ return null;
562
+ }
563
+ }
564
+ function getReader(sdk, type) {
565
+ switch (type) {
566
+ case "event":
567
+ return sdk.getEvent;
568
+ case "command":
569
+ return sdk.getCommand;
570
+ case "query":
571
+ return sdk.getQuery;
572
+ case "service":
573
+ return sdk.getService;
574
+ case "domain":
575
+ return sdk.getDomain;
576
+ case "channel":
577
+ return sdk.getChannel;
578
+ case "team":
579
+ return sdk.getTeam;
580
+ case "user":
581
+ return sdk.getUser;
582
+ default:
583
+ return null;
584
+ }
585
+ }
586
+ function promptConfirm(message) {
587
+ return new Promise((resolve4) => {
588
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
589
+ rl.question(`${message} `, (answer) => {
590
+ rl.close();
591
+ const normalized = answer.trim().toLowerCase();
592
+ resolve4(normalized === "" || normalized === "y" || normalized === "yes");
593
+ });
594
+ });
595
+ }
596
+ function promptInput(message, defaultValue) {
597
+ return new Promise((resolve4) => {
598
+ const rl = (0, import_node_readline.createInterface)({ input: process.stdin, output: process.stdout });
599
+ rl.question(`${message} `, (answer) => {
600
+ rl.close();
601
+ resolve4(answer.trim() || defaultValue);
602
+ });
603
+ });
604
+ }
605
+ function initCatalog(dir, organizationName = "My Organization") {
606
+ const catalogDir = (0, import_node_path2.resolve)(dir);
607
+ (0, import_node_fs3.mkdirSync)(catalogDir, { recursive: true });
608
+ const packageJson = {
609
+ name: "my-catalog",
610
+ version: "0.1.0",
611
+ private: true,
612
+ scripts: {
613
+ dev: "eventcatalog dev",
614
+ build: "eventcatalog build",
615
+ start: "eventcatalog start",
616
+ preview: "eventcatalog preview",
617
+ generate: "eventcatalog generate",
618
+ lint: "eventcatalog-linter",
619
+ test: 'echo "Error: no test specified" && exit 1'
620
+ },
621
+ dependencies: {
622
+ "@eventcatalog/core": "latest",
623
+ "@eventcatalog/linter": "latest"
624
+ }
625
+ };
626
+ (0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, "package.json"), JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
627
+ const cId = (0, import_node_crypto.randomUUID)();
628
+ const config = `/** @type {import('@eventcatalog/core/bin/eventcatalog.config').Config} */
629
+ export default {
630
+ title: 'EventCatalog',
631
+ tagline: 'Discover, Explore and Document your Event Driven Architectures',
632
+ organizationName: '${organizationName}',
633
+ homepageLink: 'https://eventcatalog.dev/',
634
+ output: 'static',
635
+ trailingSlash: false,
636
+ base: '/',
637
+ logo: {
638
+ alt: 'EventCatalog Logo',
639
+ src: '/logo.png',
640
+ text: 'EventCatalog',
641
+ },
642
+ cId: '${cId}',
643
+ };
644
+ `;
645
+ (0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, "eventcatalog.config.js"), config, "utf-8");
646
+ const gitignore = `# Dependencies
647
+ /node_modules
648
+
649
+ # Production
650
+ /build
651
+
652
+ # Generated files
653
+ .astro
654
+ out
655
+ dist
656
+
657
+ # Misc
658
+ .DS_Store
659
+ .env.local
660
+ .env.development.local
661
+ .env.test.local
662
+ .env.production.local
663
+
664
+ npm-debug.log*
665
+ yarn-debug.log*
666
+ yarn-error.log*
667
+
668
+ .eventcatalog-core
669
+
670
+ .env
671
+ .env-*
672
+ `;
673
+ (0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, ".gitignore"), gitignore, "utf-8");
674
+ const envFile = `# EventCatalog Scale License Key, if you want to unlock the scale features
675
+ # You can get a 14 day trial license key from https://eventcatalog.cloud
676
+
677
+ EVENTCATALOG_SCALE_LICENSE_KEY=
678
+
679
+ # Optional key if you are using EventCatalog Chat with OpenAI Models.
680
+ # You need to set \`output\` to \`server\` in your eventcatalog.config.js file.
681
+ # See documentation for more details: https://www.eventcatalog.dev/features/ai-assistant
682
+ OPENAI_API_KEY=
683
+ `;
684
+ (0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, ".env"), envFile, "utf-8");
685
+ (0, import_node_fs3.writeFileSync)((0, import_node_path2.join)(catalogDir, ".npmrc"), "strict-peer-dependencies=false\n", "utf-8");
686
+ (0, import_node_fs3.mkdirSync)((0, import_node_path2.join)(catalogDir, "public"), { recursive: true });
687
+ (0, import_node_fs3.copyFileSync)((0, import_node_path2.join)(__dirname, "logo.png"), (0, import_node_path2.join)(catalogDir, "public", "logo.png"));
688
+ }
689
+ async function importDSL(options) {
690
+ const { files, stdin = false, dryRun = false, flat = false, noInit = false, dir } = options;
691
+ const nested = !flat;
692
+ let source;
693
+ if (stdin) {
694
+ source = await readStdin();
695
+ } else if (files && files.length > 0) {
696
+ const parts = [];
697
+ for (const file of files) {
698
+ const filepath = (0, import_node_path2.resolve)(file);
699
+ if (!(0, import_node_fs3.existsSync)(filepath)) {
700
+ throw new Error(`File not found: ${filepath}`);
701
+ }
702
+ parts.push((0, import_node_fs3.readFileSync)(filepath, "utf-8"));
703
+ }
704
+ source = parts.join("\n\n");
705
+ } else {
706
+ throw new Error("Either provide .ec file paths or use --stdin");
707
+ }
708
+ if (!source.trim()) {
709
+ throw new Error("No DSL content to import");
710
+ }
711
+ const catalogDir = (0, import_node_path2.resolve)(dir);
712
+ let didInit = false;
713
+ if (!noInit && !(0, import_node_fs3.existsSync)((0, import_node_path2.join)(catalogDir, "eventcatalog.config.js")) && process.stdin.isTTY) {
714
+ const confirmed = await promptConfirm(`Initialize a new EventCatalog at ${catalogDir}? (Y/n)`);
715
+ if (confirmed) {
716
+ const organizationName = await promptInput("Organization name (My Organization):", "My Organization");
717
+ initCatalog(dir, organizationName);
718
+ didInit = true;
719
+ }
720
+ }
721
+ const outputs = await parseDSL(source, { nested });
722
+ if (outputs.length === 0) {
723
+ throw new Error("No resources found in DSL content");
724
+ }
725
+ const sdk = (0, import_sdk4.default)(catalogDir);
726
+ const result = { created: [], updated: [], versioned: [], errors: [] };
727
+ const resources = outputs.map(parseCompiledOutput);
728
+ const compiledIds = new Set(resources.map((r) => `${r.type}:${r.id}`));
729
+ const stubs = await extractMessageStubs(source, compiledIds, nested);
730
+ resources.push(...stubs);
731
+ for (const resource of resources) {
732
+ const label = resource.version ? `${resource.type} ${resource.id}@${resource.version}` : `${resource.type} ${resource.id}`;
733
+ if (dryRun) {
734
+ const reader = getReader(sdk, resource.type);
735
+ if (reader) {
736
+ const existing = await reader(resource.id, resource.version).catch(() => void 0);
737
+ if (existing) {
738
+ result.updated.push(label);
739
+ } else {
740
+ const latest = await reader(resource.id).catch(() => void 0);
741
+ if (latest && latest.version && latest.version !== resource.version) {
742
+ result.versioned.push(`${resource.type} ${resource.id}@${latest.version}`);
743
+ }
744
+ result.created.push(label);
745
+ }
746
+ } else {
747
+ result.created.push(label);
748
+ }
749
+ continue;
750
+ }
751
+ const writer = getWriter(sdk, resource.type);
752
+ if (!writer) {
753
+ result.errors.push(`${label}: unsupported resource type '${resource.type}'`);
754
+ continue;
755
+ }
756
+ try {
757
+ const reader = getReader(sdk, resource.type);
758
+ const existing = reader ? await reader(resource.id, resource.version).catch(() => void 0) : void 0;
759
+ let markdown = resource.markdown;
760
+ if (!existing && TYPES_WITH_NODE_GRAPH.has(resource.type)) {
761
+ markdown = markdown ? `${markdown}
762
+
763
+ <NodeGraph />` : "<NodeGraph />";
764
+ }
765
+ const resourceData = {
766
+ ...resource.frontmatter,
767
+ markdown
768
+ };
769
+ const writeOptions = {
770
+ override: true,
771
+ versionExistingContent: true
772
+ };
773
+ if (!existing && nested) {
774
+ const sdkPath = extractSdkPath(resource.path, resource.type);
775
+ if (sdkPath) {
776
+ writeOptions.path = sdkPath;
777
+ }
778
+ }
779
+ await writer(resourceData, writeOptions);
780
+ if (existing) {
781
+ result.updated.push(label);
782
+ } else {
783
+ result.created.push(label);
784
+ }
785
+ } catch (error) {
786
+ result.errors.push(`${label}: ${error instanceof Error ? error.message : String(error)}`);
787
+ }
788
+ }
789
+ let output = formatResult(result, dryRun);
790
+ if (didInit) {
791
+ output += ` Tip: Run 'npm install' in ${catalogDir} to install dependencies
792
+ `;
793
+ }
794
+ return output;
795
+ }
796
+ var c = {
797
+ reset: "\x1B[0m",
798
+ bold: "\x1B[1m",
799
+ dim: "\x1B[2m",
800
+ green: "\x1B[32m",
801
+ yellow: "\x1B[33m",
802
+ blue: "\x1B[34m",
803
+ magenta: "\x1B[35m",
804
+ cyan: "\x1B[36m",
805
+ red: "\x1B[31m",
806
+ white: "\x1B[37m",
807
+ gray: "\x1B[90m"
808
+ };
809
+ var TYPE_CONFIG = {
810
+ domain: { color: c.magenta, label: "domain", order: 0 },
811
+ service: { color: c.blue, label: "service", order: 1 },
812
+ event: { color: c.green, label: "event", order: 2 },
813
+ command: { color: c.yellow, label: "command", order: 3 },
814
+ query: { color: c.cyan, label: "query", order: 4 },
815
+ channel: { color: c.gray, label: "channel", order: 5 },
816
+ flow: { color: c.white, label: "flow", order: 6 },
817
+ user: { color: c.blue, label: "user", order: 7 },
818
+ team: { color: c.blue, label: "team", order: 8 }
819
+ };
820
+ var DEFAULT_TYPE_CONFIG = { color: c.white, label: "resource", order: 99 };
821
+ function parseLabel(label) {
822
+ const spaceIdx = label.indexOf(" ");
823
+ if (spaceIdx === -1) return { type: "", name: label };
824
+ return { type: label.slice(0, spaceIdx), name: label.slice(spaceIdx + 1) };
825
+ }
826
+ function groupByType(labels) {
827
+ const groups = /* @__PURE__ */ new Map();
828
+ for (const label of labels) {
829
+ const { type, name } = parseLabel(label);
830
+ if (!groups.has(type)) groups.set(type, []);
831
+ groups.get(type).push(name);
832
+ }
833
+ const sorted = new Map(
834
+ [...groups.entries()].sort((a, b) => {
835
+ const orderA = (TYPE_CONFIG[a[0]] || DEFAULT_TYPE_CONFIG).order;
836
+ const orderB = (TYPE_CONFIG[b[0]] || DEFAULT_TYPE_CONFIG).order;
837
+ return orderA - orderB;
838
+ })
839
+ );
840
+ for (const [, names] of sorted) {
841
+ names.sort();
842
+ }
843
+ return sorted;
844
+ }
845
+ function typeBadge(type) {
846
+ const cfg = TYPE_CONFIG[type] || DEFAULT_TYPE_CONFIG;
847
+ const padded = ` ${cfg.label} `;
848
+ return `${cfg.color}\x1B[7m${padded}${c.reset}`;
849
+ }
850
+ function formatResourceList(labels) {
851
+ const lines = [];
852
+ const groups = groupByType(labels);
853
+ for (const [type, names] of groups) {
854
+ const cfg = TYPE_CONFIG[type] || DEFAULT_TYPE_CONFIG;
855
+ const plural = names.length === 1 ? cfg.label : `${cfg.label}s`;
856
+ lines.push("");
857
+ lines.push(` ${typeBadge(type)} ${c.dim}${names.length} ${plural}${c.reset}`);
858
+ for (const name of names) {
859
+ lines.push(` ${cfg.color}\u2502${c.reset} ${name}`);
860
+ }
861
+ }
862
+ return lines;
863
+ }
864
+ function formatResult(result, dryRun) {
865
+ const lines = [""];
866
+ const prefix = dryRun ? `${c.yellow}${c.bold}DRY RUN${c.reset} ` : "";
867
+ const total = result.created.length + result.updated.length + result.versioned.length;
868
+ if (total > 0 || result.errors.length > 0) {
869
+ lines.push(` ${prefix}${c.bold}Import complete${c.reset}`);
870
+ lines.push(` ${c.dim}${"\u2500".repeat(40)}${c.reset}`);
871
+ }
872
+ if (result.created.length > 0) {
873
+ const verb = dryRun ? "Would create" : "Created";
874
+ lines.push("");
875
+ lines.push(` ${c.green}${c.bold}+ ${verb} ${result.created.length} resource(s)${c.reset}`);
876
+ lines.push(...formatResourceList(result.created));
877
+ }
878
+ if (result.updated.length > 0) {
879
+ const verb = dryRun ? "Would update" : "Updated";
880
+ lines.push("");
881
+ lines.push(` ${c.blue}${c.bold}~ ${verb} ${result.updated.length} resource(s)${c.reset}`);
882
+ lines.push(...formatResourceList(result.updated));
883
+ }
884
+ if (result.versioned.length > 0) {
885
+ const verb = dryRun ? "Would version" : "Versioned";
886
+ lines.push("");
887
+ lines.push(` ${c.yellow}${c.bold}\u2191 ${verb} ${result.versioned.length} existing resource(s)${c.reset}`);
888
+ lines.push(...formatResourceList(result.versioned));
889
+ }
890
+ if (result.errors.length > 0) {
891
+ lines.push("");
892
+ lines.push(` ${c.red}${c.bold}\u2718 ${result.errors.length} error(s)${c.reset}`);
893
+ for (const e of result.errors) {
894
+ lines.push(` ${c.red}\u2502${c.reset} ${c.red}${e}${c.reset}`);
895
+ }
896
+ }
897
+ if (result.created.length === 0 && result.updated.length === 0 && result.errors.length === 0) {
898
+ lines.push(` ${c.dim}No resources to write.${c.reset}`);
899
+ }
900
+ lines.push("");
901
+ return lines.join("\n");
902
+ }
903
+ function readStdin() {
904
+ return new Promise((resolve4, reject) => {
905
+ const chunks = [];
906
+ process.stdin.on("data", (chunk) => chunks.push(chunk));
907
+ process.stdin.on("end", () => resolve4(Buffer.concat(chunks).toString("utf-8")));
908
+ process.stdin.on("error", reject);
909
+ });
910
+ }
911
+
355
912
  // src/cli/index.ts
356
913
  var version = "1.0.0";
357
914
  try {
358
- const packageJsonPath = (0, import_node_path2.resolve)(__dirname, "../../package.json");
359
- const packageJson = JSON.parse((0, import_node_fs3.readFileSync)(packageJsonPath, "utf-8"));
915
+ const packageJsonPath = (0, import_node_path3.resolve)(__dirname, "../../package.json");
916
+ const packageJson = JSON.parse((0, import_node_fs4.readFileSync)(packageJsonPath, "utf-8"));
360
917
  version = packageJson.version;
361
918
  } catch {
362
919
  }
@@ -406,6 +963,24 @@ import_commander.program.command("export").description("Export a catalog resourc
406
963
  process.exit(1);
407
964
  }
408
965
  });
966
+ import_commander.program.command("import [files...]").description("Import EventCatalog DSL (.ec) files into catalog markdown").option("--stdin", "Read DSL from stdin", false).option("--dry-run", "Preview resources without writing", false).option("--flat", "Write resources in flat structure (no nesting under domains/services)", false).option("--no-init", "Skip catalog initialization prompt").action(async (files, opts) => {
967
+ try {
968
+ const globalOpts = import_commander.program.opts();
969
+ const dir = globalOpts.dir || ".";
970
+ const result = await importDSL({
971
+ files: files.length > 0 ? files : void 0,
972
+ stdin: opts.stdin,
973
+ dryRun: opts.dryRun,
974
+ flat: opts.flat,
975
+ noInit: !opts.init,
976
+ dir
977
+ });
978
+ console.log(result);
979
+ } catch (error) {
980
+ console.error(error instanceof Error ? error.message : String(error));
981
+ process.exit(1);
982
+ }
983
+ });
409
984
  import_commander.program.arguments("<function> [args...]").action(async (functionName, args) => {
410
985
  try {
411
986
  const options = import_commander.program.opts();