@hasna/microservices 0.0.19 → 0.0.21

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/bin/index.js CHANGED
@@ -33,7 +33,7 @@ var __toESM = (mod, isNodeMode, target) => {
33
33
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
34
  var __require = import.meta.require;
35
35
 
36
- // node_modules/commander/lib/error.js
36
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/error.js
37
37
  var require_error = __commonJS((exports) => {
38
38
  class CommanderError extends Error {
39
39
  constructor(exitCode, code, message) {
@@ -57,7 +57,7 @@ var require_error = __commonJS((exports) => {
57
57
  exports.InvalidArgumentError = InvalidArgumentError;
58
58
  });
59
59
 
60
- // node_modules/commander/lib/argument.js
60
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/argument.js
61
61
  var require_argument = __commonJS((exports) => {
62
62
  var { InvalidArgumentError } = require_error();
63
63
 
@@ -136,7 +136,7 @@ var require_argument = __commonJS((exports) => {
136
136
  exports.humanReadableArgName = humanReadableArgName;
137
137
  });
138
138
 
139
- // node_modules/commander/lib/help.js
139
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/help.js
140
140
  var require_help = __commonJS((exports) => {
141
141
  var { humanReadableArgName } = require_argument();
142
142
 
@@ -385,7 +385,7 @@ var require_help = __commonJS((exports) => {
385
385
  exports.Help = Help;
386
386
  });
387
387
 
388
- // node_modules/commander/lib/option.js
388
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/option.js
389
389
  var require_option = __commonJS((exports) => {
390
390
  var { InvalidArgumentError } = require_error();
391
391
 
@@ -536,7 +536,7 @@ var require_option = __commonJS((exports) => {
536
536
  exports.DualOptions = DualOptions;
537
537
  });
538
538
 
539
- // node_modules/commander/lib/suggestSimilar.js
539
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/suggestSimilar.js
540
540
  var require_suggestSimilar = __commonJS((exports) => {
541
541
  var maxDistance = 3;
542
542
  function editDistance(a, b) {
@@ -609,13 +609,13 @@ var require_suggestSimilar = __commonJS((exports) => {
609
609
  exports.suggestSimilar = suggestSimilar;
610
610
  });
611
611
 
612
- // node_modules/commander/lib/command.js
612
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/lib/command.js
613
613
  var require_command = __commonJS((exports) => {
614
614
  var EventEmitter = __require("events").EventEmitter;
615
615
  var childProcess = __require("child_process");
616
616
  var path = __require("path");
617
617
  var fs = __require("fs");
618
- var process2 = __require("process");
618
+ var process3 = __require("process");
619
619
  var { Argument, humanReadableArgName } = require_argument();
620
620
  var { CommanderError } = require_error();
621
621
  var { Help } = require_help();
@@ -657,10 +657,10 @@ var require_command = __commonJS((exports) => {
657
657
  this._showHelpAfterError = false;
658
658
  this._showSuggestionAfterError = true;
659
659
  this._outputConfiguration = {
660
- writeOut: (str) => process2.stdout.write(str),
661
- writeErr: (str) => process2.stderr.write(str),
662
- getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined,
663
- getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined,
660
+ writeOut: (str) => process3.stdout.write(str),
661
+ writeErr: (str) => process3.stderr.write(str),
662
+ getOutHelpWidth: () => process3.stdout.isTTY ? process3.stdout.columns : undefined,
663
+ getErrHelpWidth: () => process3.stderr.isTTY ? process3.stderr.columns : undefined,
664
664
  outputError: (str, write) => write(str)
665
665
  };
666
666
  this._hidden = false;
@@ -856,7 +856,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
856
856
  if (this._exitCallback) {
857
857
  this._exitCallback(new CommanderError(exitCode, code, message));
858
858
  }
859
- process2.exit(exitCode);
859
+ process3.exit(exitCode);
860
860
  }
861
861
  action(fn) {
862
862
  const listener = (args) => {
@@ -1051,16 +1051,16 @@ Expecting one of '${allowedValues.join("', '")}'`);
1051
1051
  }
1052
1052
  parseOptions = parseOptions || {};
1053
1053
  if (argv === undefined && parseOptions.from === undefined) {
1054
- if (process2.versions?.electron) {
1054
+ if (process3.versions?.electron) {
1055
1055
  parseOptions.from = "electron";
1056
1056
  }
1057
- const execArgv = process2.execArgv ?? [];
1057
+ const execArgv = process3.execArgv ?? [];
1058
1058
  if (execArgv.includes("-e") || execArgv.includes("--eval") || execArgv.includes("-p") || execArgv.includes("--print")) {
1059
1059
  parseOptions.from = "eval";
1060
1060
  }
1061
1061
  }
1062
1062
  if (argv === undefined) {
1063
- argv = process2.argv;
1063
+ argv = process3.argv;
1064
1064
  }
1065
1065
  this.rawArgs = argv.slice();
1066
1066
  let userArgs;
@@ -1071,7 +1071,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1071
1071
  userArgs = argv.slice(2);
1072
1072
  break;
1073
1073
  case "electron":
1074
- if (process2.defaultApp) {
1074
+ if (process3.defaultApp) {
1075
1075
  this._scriptPath = argv[1];
1076
1076
  userArgs = argv.slice(2);
1077
1077
  } else {
@@ -1142,23 +1142,23 @@ Expecting one of '${allowedValues.join("', '")}'`);
1142
1142
  }
1143
1143
  launchWithNode = sourceExt.includes(path.extname(executableFile));
1144
1144
  let proc;
1145
- if (process2.platform !== "win32") {
1145
+ if (process3.platform !== "win32") {
1146
1146
  if (launchWithNode) {
1147
1147
  args.unshift(executableFile);
1148
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1149
- proc = childProcess.spawn(process2.argv[0], args, { stdio: "inherit" });
1148
+ args = incrementNodeInspectorPort(process3.execArgv).concat(args);
1149
+ proc = childProcess.spawn(process3.argv[0], args, { stdio: "inherit" });
1150
1150
  } else {
1151
1151
  proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
1152
1152
  }
1153
1153
  } else {
1154
1154
  args.unshift(executableFile);
1155
- args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1156
- proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
1155
+ args = incrementNodeInspectorPort(process3.execArgv).concat(args);
1156
+ proc = childProcess.spawn(process3.execPath, args, { stdio: "inherit" });
1157
1157
  }
1158
1158
  if (!proc.killed) {
1159
1159
  const signals = ["SIGUSR1", "SIGUSR2", "SIGTERM", "SIGINT", "SIGHUP"];
1160
1160
  signals.forEach((signal) => {
1161
- process2.on(signal, () => {
1161
+ process3.on(signal, () => {
1162
1162
  if (proc.killed === false && proc.exitCode === null) {
1163
1163
  proc.kill(signal);
1164
1164
  }
@@ -1169,7 +1169,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1169
1169
  proc.on("close", (code) => {
1170
1170
  code = code ?? 1;
1171
1171
  if (!exitCallback) {
1172
- process2.exit(code);
1172
+ process3.exit(code);
1173
1173
  } else {
1174
1174
  exitCallback(new CommanderError(code, "commander.executeSubCommandAsync", "(close)"));
1175
1175
  }
@@ -1186,7 +1186,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1186
1186
  throw new Error(`'${executableFile}' not executable`);
1187
1187
  }
1188
1188
  if (!exitCallback) {
1189
- process2.exit(1);
1189
+ process3.exit(1);
1190
1190
  } else {
1191
1191
  const wrappedError = new CommanderError(1, "commander.executeSubCommandAsync", "(error)");
1192
1192
  wrappedError.nestedError = err;
@@ -1534,11 +1534,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1534
1534
  }
1535
1535
  _parseOptionsEnv() {
1536
1536
  this.options.forEach((option) => {
1537
- if (option.envVar && option.envVar in process2.env) {
1537
+ if (option.envVar && option.envVar in process3.env) {
1538
1538
  const optionKey = option.attributeName();
1539
1539
  if (this.getOptionValue(optionKey) === undefined || ["default", "config", "env"].includes(this.getOptionValueSource(optionKey))) {
1540
1540
  if (option.required || option.optional) {
1541
- this.emit(`optionEnv:${option.name()}`, process2.env[option.envVar]);
1541
+ this.emit(`optionEnv:${option.name()}`, process3.env[option.envVar]);
1542
1542
  } else {
1543
1543
  this.emit(`optionEnv:${option.name()}`);
1544
1544
  }
@@ -1784,7 +1784,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1784
1784
  }
1785
1785
  help(contextOptions) {
1786
1786
  this.outputHelp(contextOptions);
1787
- let exitCode = process2.exitCode || 0;
1787
+ let exitCode = process3.exitCode || 0;
1788
1788
  if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
1789
1789
  exitCode = 1;
1790
1790
  }
@@ -1852,7 +1852,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1852
1852
  exports.Command = Command;
1853
1853
  });
1854
1854
 
1855
- // node_modules/commander/index.js
1855
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/index.js
1856
1856
  var require_commander = __commonJS((exports) => {
1857
1857
  var { Argument } = require_argument();
1858
1858
  var { Command } = require_command();
@@ -1872,23 +1872,11 @@ var require_commander = __commonJS((exports) => {
1872
1872
  exports.InvalidOptionArgumentError = InvalidArgumentError;
1873
1873
  });
1874
1874
 
1875
- // node_modules/commander/esm.mjs
1876
- var import__ = __toESM(require_commander(), 1);
1877
- var {
1878
- program,
1879
- createCommand,
1880
- createArgument,
1881
- createOption,
1882
- CommanderError,
1883
- InvalidArgumentError,
1884
- InvalidOptionArgumentError,
1885
- Command,
1886
- Argument,
1887
- Option,
1888
- Help
1889
- } = import__.default;
1875
+ // src/cli/index.tsx
1876
+ import fs from "fs";
1877
+ import path from "path";
1890
1878
 
1891
- // node_modules/chalk/source/vendor/ansi-styles/index.js
1879
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
1892
1880
  var ANSI_BACKGROUND_OFFSET = 10;
1893
1881
  var wrapAnsi16 = (offset = 0) => (code) => `\x1B[${code + offset}m`;
1894
1882
  var wrapAnsi256 = (offset = 0) => (code) => `\x1B[${38 + offset};5;${code}m`;
@@ -2065,7 +2053,7 @@ function assembleStyles() {
2065
2053
  var ansiStyles = assembleStyles();
2066
2054
  var ansi_styles_default = ansiStyles;
2067
2055
 
2068
- // node_modules/chalk/source/vendor/supports-color/index.js
2056
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
2069
2057
  import process2 from "process";
2070
2058
  import os from "os";
2071
2059
  import tty from "tty";
@@ -2197,7 +2185,7 @@ var supportsColor = {
2197
2185
  };
2198
2186
  var supports_color_default = supportsColor;
2199
2187
 
2200
- // node_modules/chalk/source/utilities.js
2188
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/utilities.js
2201
2189
  function stringReplaceAll(string, substring, replacer) {
2202
2190
  let index = string.indexOf(substring);
2203
2191
  if (index === -1) {
@@ -2230,7 +2218,7 @@ function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
2230
2218
  return returnValue;
2231
2219
  }
2232
2220
 
2233
- // node_modules/chalk/source/index.js
2221
+ // node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/index.js
2234
2222
  var { stdout: stdoutColor, stderr: stderrColor } = supports_color_default;
2235
2223
  var GENERATOR = Symbol("GENERATOR");
2236
2224
  var STYLER = Symbol("STYLER");
@@ -2377,6 +2365,27 @@ var chalk = createChalk();
2377
2365
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
2378
2366
  var source_default = chalk;
2379
2367
 
2368
+ // node_modules/.bun/commander@12.1.0/node_modules/commander/esm.mjs
2369
+ var import__ = __toESM(require_commander(), 1);
2370
+ var {
2371
+ program,
2372
+ createCommand,
2373
+ createArgument,
2374
+ createOption,
2375
+ CommanderError,
2376
+ InvalidArgumentError,
2377
+ InvalidOptionArgumentError,
2378
+ Command,
2379
+ Argument,
2380
+ Option,
2381
+ Help
2382
+ } = import__.default;
2383
+
2384
+ // src/lib/installer.ts
2385
+ import { execFileSync, execSync } from "child_process";
2386
+ import { accessSync, constants } from "fs";
2387
+ import { join } from "path";
2388
+
2380
2389
  // src/lib/registry.ts
2381
2390
  var MICROSERVICES = [
2382
2391
  {
@@ -2387,9 +2396,24 @@ var MICROSERVICES = [
2387
2396
  package: "@hasna/microservice-auth",
2388
2397
  binary: "microservice-auth",
2389
2398
  schemaPrefix: "auth",
2390
- tags: ["auth", "users", "sessions", "jwt", "oauth", "2fa", "api-keys", "magic-links"],
2399
+ tags: [
2400
+ "auth",
2401
+ "users",
2402
+ "sessions",
2403
+ "jwt",
2404
+ "oauth",
2405
+ "2fa",
2406
+ "api-keys",
2407
+ "magic-links"
2408
+ ],
2391
2409
  requiredEnv: ["DATABASE_URL", "JWT_SECRET"],
2392
- optionalEnv: ["GITHUB_CLIENT_ID", "GITHUB_CLIENT_SECRET", "GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "AUTH_PORT"]
2410
+ optionalEnv: [
2411
+ "GITHUB_CLIENT_ID",
2412
+ "GITHUB_CLIENT_SECRET",
2413
+ "GOOGLE_CLIENT_ID",
2414
+ "GOOGLE_CLIENT_SECRET",
2415
+ "AUTH_PORT"
2416
+ ]
2393
2417
  },
2394
2418
  {
2395
2419
  name: "teams",
@@ -2399,7 +2423,14 @@ var MICROSERVICES = [
2399
2423
  package: "@hasna/microservice-teams",
2400
2424
  binary: "microservice-teams",
2401
2425
  schemaPrefix: "teams",
2402
- tags: ["teams", "workspaces", "rbac", "invites", "permissions", "multi-tenancy"],
2426
+ tags: [
2427
+ "teams",
2428
+ "workspaces",
2429
+ "rbac",
2430
+ "invites",
2431
+ "permissions",
2432
+ "multi-tenancy"
2433
+ ],
2403
2434
  requiredEnv: ["DATABASE_URL"],
2404
2435
  optionalEnv: ["TEAMS_PORT"]
2405
2436
  },
@@ -2411,7 +2442,15 @@ var MICROSERVICES = [
2411
2442
  package: "@hasna/microservice-billing",
2412
2443
  binary: "microservice-billing",
2413
2444
  schemaPrefix: "billing",
2414
- tags: ["billing", "stripe", "subscriptions", "plans", "invoices", "usage", "webhooks"],
2445
+ tags: [
2446
+ "billing",
2447
+ "stripe",
2448
+ "subscriptions",
2449
+ "plans",
2450
+ "invoices",
2451
+ "usage",
2452
+ "webhooks"
2453
+ ],
2415
2454
  requiredEnv: ["DATABASE_URL", "STRIPE_SECRET_KEY", "STRIPE_WEBHOOK_SECRET"],
2416
2455
  optionalEnv: ["BILLING_PORT"]
2417
2456
  },
@@ -2423,9 +2462,26 @@ var MICROSERVICES = [
2423
2462
  package: "@hasna/microservice-notify",
2424
2463
  binary: "microservice-notify",
2425
2464
  schemaPrefix: "notify",
2426
- tags: ["notifications", "email", "sms", "in-app", "webhooks", "templates", "sse"],
2465
+ tags: [
2466
+ "notifications",
2467
+ "email",
2468
+ "sms",
2469
+ "in-app",
2470
+ "webhooks",
2471
+ "templates",
2472
+ "sse"
2473
+ ],
2427
2474
  requiredEnv: ["DATABASE_URL"],
2428
- optionalEnv: ["RESEND_API_KEY", "SMTP_HOST", "SMTP_PORT", "SMTP_USER", "SMTP_PASS", "TWILIO_ACCOUNT_SID", "TWILIO_AUTH_TOKEN", "NOTIFY_PORT"]
2475
+ optionalEnv: [
2476
+ "RESEND_API_KEY",
2477
+ "SMTP_HOST",
2478
+ "SMTP_PORT",
2479
+ "SMTP_USER",
2480
+ "SMTP_PASS",
2481
+ "TWILIO_ACCOUNT_SID",
2482
+ "TWILIO_AUTH_TOKEN",
2483
+ "NOTIFY_PORT"
2484
+ ]
2429
2485
  },
2430
2486
  {
2431
2487
  name: "files",
@@ -2435,9 +2491,24 @@ var MICROSERVICES = [
2435
2491
  package: "@hasna/microservice-files",
2436
2492
  binary: "microservice-files",
2437
2493
  schemaPrefix: "files",
2438
- tags: ["files", "uploads", "s3", "storage", "images", "presigned-urls", "cdn"],
2494
+ tags: [
2495
+ "files",
2496
+ "uploads",
2497
+ "s3",
2498
+ "storage",
2499
+ "images",
2500
+ "presigned-urls",
2501
+ "cdn"
2502
+ ],
2439
2503
  requiredEnv: ["DATABASE_URL"],
2440
- optionalEnv: ["S3_BUCKET", "S3_REGION", "AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "FILES_STORAGE", "FILES_PORT"]
2504
+ optionalEnv: [
2505
+ "S3_BUCKET",
2506
+ "S3_REGION",
2507
+ "AWS_ACCESS_KEY_ID",
2508
+ "AWS_SECRET_ACCESS_KEY",
2509
+ "FILES_STORAGE",
2510
+ "FILES_PORT"
2511
+ ]
2441
2512
  },
2442
2513
  {
2443
2514
  name: "audit",
@@ -2459,7 +2530,13 @@ var MICROSERVICES = [
2459
2530
  package: "@hasna/microservice-flags",
2460
2531
  binary: "microservice-flags",
2461
2532
  schemaPrefix: "flags",
2462
- tags: ["feature-flags", "experiments", "rollouts", "ab-testing", "targeting"],
2533
+ tags: [
2534
+ "feature-flags",
2535
+ "experiments",
2536
+ "rollouts",
2537
+ "ab-testing",
2538
+ "targeting"
2539
+ ],
2463
2540
  requiredEnv: ["DATABASE_URL"],
2464
2541
  optionalEnv: ["FLAGS_PORT"]
2465
2542
  },
@@ -2471,7 +2548,15 @@ var MICROSERVICES = [
2471
2548
  package: "@hasna/microservice-jobs",
2472
2549
  binary: "microservice-jobs",
2473
2550
  schemaPrefix: "jobs",
2474
- tags: ["jobs", "queues", "background", "cron", "scheduling", "workers", "retry"],
2551
+ tags: [
2552
+ "jobs",
2553
+ "queues",
2554
+ "background",
2555
+ "cron",
2556
+ "scheduling",
2557
+ "workers",
2558
+ "retry"
2559
+ ],
2475
2560
  requiredEnv: ["DATABASE_URL"],
2476
2561
  optionalEnv: ["JOBS_PORT", "JOBS_WORKER_CONCURRENCY"]
2477
2562
  },
@@ -2483,9 +2568,23 @@ var MICROSERVICES = [
2483
2568
  package: "@hasna/microservice-llm",
2484
2569
  binary: "microservice-llm",
2485
2570
  schemaPrefix: "llm",
2486
- tags: ["llm", "openai", "anthropic", "groq", "ai", "gateway", "cost-tracking", "rate-limiting"],
2571
+ tags: [
2572
+ "llm",
2573
+ "openai",
2574
+ "anthropic",
2575
+ "groq",
2576
+ "ai",
2577
+ "gateway",
2578
+ "cost-tracking",
2579
+ "rate-limiting"
2580
+ ],
2487
2581
  requiredEnv: ["DATABASE_URL"],
2488
- optionalEnv: ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GROQ_API_KEY", "LLM_PORT"]
2582
+ optionalEnv: [
2583
+ "OPENAI_API_KEY",
2584
+ "ANTHROPIC_API_KEY",
2585
+ "GROQ_API_KEY",
2586
+ "LLM_PORT"
2587
+ ]
2489
2588
  },
2490
2589
  {
2491
2590
  name: "memory",
@@ -2495,7 +2594,15 @@ var MICROSERVICES = [
2495
2594
  package: "@hasna/microservice-memory",
2496
2595
  binary: "microservice-memory",
2497
2596
  schemaPrefix: "memory",
2498
- tags: ["memory", "embeddings", "pgvector", "semantic-search", "rag", "ai-agents", "recall"],
2597
+ tags: [
2598
+ "memory",
2599
+ "embeddings",
2600
+ "pgvector",
2601
+ "semantic-search",
2602
+ "rag",
2603
+ "ai-agents",
2604
+ "recall"
2605
+ ],
2499
2606
  requiredEnv: ["DATABASE_URL"],
2500
2607
  optionalEnv: ["OPENAI_API_KEY", "MEMORY_PORT"]
2501
2608
  },
@@ -2507,7 +2614,15 @@ var MICROSERVICES = [
2507
2614
  package: "@hasna/microservice-search",
2508
2615
  binary: "microservice-search",
2509
2616
  schemaPrefix: "search",
2510
- tags: ["search", "full-text", "semantic", "vector", "pgvector", "hybrid", "rag"],
2617
+ tags: [
2618
+ "search",
2619
+ "full-text",
2620
+ "semantic",
2621
+ "vector",
2622
+ "pgvector",
2623
+ "hybrid",
2624
+ "rag"
2625
+ ],
2511
2626
  requiredEnv: ["DATABASE_URL"],
2512
2627
  optionalEnv: ["OPENAI_API_KEY", "SEARCH_PORT"]
2513
2628
  },
@@ -2519,7 +2634,15 @@ var MICROSERVICES = [
2519
2634
  package: "@hasna/microservice-knowledge",
2520
2635
  binary: "microservice-knowledge",
2521
2636
  schemaPrefix: "knowledge",
2522
- tags: ["knowledge", "rag", "chunking", "embeddings", "retrieval", "pgvector", "documents"],
2637
+ tags: [
2638
+ "knowledge",
2639
+ "rag",
2640
+ "chunking",
2641
+ "embeddings",
2642
+ "retrieval",
2643
+ "pgvector",
2644
+ "documents"
2645
+ ],
2523
2646
  requiredEnv: ["DATABASE_URL"],
2524
2647
  optionalEnv: ["OPENAI_API_KEY", "KNOWLEDGE_PORT"]
2525
2648
  },
@@ -2543,7 +2666,14 @@ var MICROSERVICES = [
2543
2666
  package: "@hasna/microservice-webhooks",
2544
2667
  binary: "microservice-webhooks",
2545
2668
  schemaPrefix: "webhooks",
2546
- tags: ["webhooks", "outbound", "delivery", "retry", "signing", "integrations"],
2669
+ tags: [
2670
+ "webhooks",
2671
+ "outbound",
2672
+ "delivery",
2673
+ "retry",
2674
+ "signing",
2675
+ "integrations"
2676
+ ],
2547
2677
  requiredEnv: ["DATABASE_URL"],
2548
2678
  optionalEnv: ["WEBHOOKS_PORT"]
2549
2679
  },
@@ -2579,7 +2709,14 @@ var MICROSERVICES = [
2579
2709
  package: "@hasna/microservice-sessions",
2580
2710
  binary: "microservice-sessions",
2581
2711
  schemaPrefix: "sessions",
2582
- tags: ["sessions", "conversations", "chat", "messages", "context-window", "history"],
2712
+ tags: [
2713
+ "sessions",
2714
+ "conversations",
2715
+ "chat",
2716
+ "messages",
2717
+ "context-window",
2718
+ "history"
2719
+ ],
2583
2720
  requiredEnv: ["DATABASE_URL"],
2584
2721
  optionalEnv: ["SESSIONS_PORT"]
2585
2722
  },
@@ -2591,22 +2728,18 @@ var MICROSERVICES = [
2591
2728
  package: "@hasna/microservice-guardrails",
2592
2729
  binary: "microservice-guardrails",
2593
2730
  schemaPrefix: "guardrails",
2594
- tags: ["guardrails", "safety", "pii", "injection", "toxicity", "moderation", "policy"],
2731
+ tags: [
2732
+ "guardrails",
2733
+ "safety",
2734
+ "pii",
2735
+ "injection",
2736
+ "toxicity",
2737
+ "moderation",
2738
+ "policy"
2739
+ ],
2595
2740
  requiredEnv: ["DATABASE_URL"],
2596
2741
  optionalEnv: ["GUARDRAILS_PORT"]
2597
2742
  },
2598
- {
2599
- name: "knowledge",
2600
- displayName: "Knowledge",
2601
- description: "RAG pipeline: document ingestion, chunking (fixed/paragraph/sentence/recursive), embedding via pgvector, retrieval with source attribution and scoring.",
2602
- category: "AI",
2603
- package: "@hasna/microservice-knowledge",
2604
- binary: "microservice-knowledge",
2605
- schemaPrefix: "knowledge",
2606
- tags: ["knowledge", "rag", "chunking", "ingestion", "retrieval", "documents", "pgvector"],
2607
- requiredEnv: ["DATABASE_URL"],
2608
- optionalEnv: ["OPENAI_API_KEY", "KNOWLEDGE_PORT"]
2609
- },
2610
2743
  {
2611
2744
  name: "traces",
2612
2745
  displayName: "Traces",
@@ -2615,7 +2748,15 @@ var MICROSERVICES = [
2615
2748
  package: "@hasna/microservice-traces",
2616
2749
  binary: "microservice-traces",
2617
2750
  schemaPrefix: "traces",
2618
- tags: ["traces", "tracing", "spans", "observability", "latency", "debugging", "agent-ops"],
2751
+ tags: [
2752
+ "traces",
2753
+ "tracing",
2754
+ "spans",
2755
+ "observability",
2756
+ "latency",
2757
+ "debugging",
2758
+ "agent-ops"
2759
+ ],
2619
2760
  requiredEnv: ["DATABASE_URL"],
2620
2761
  optionalEnv: ["TRACES_PORT"]
2621
2762
  },
@@ -2627,7 +2768,15 @@ var MICROSERVICES = [
2627
2768
  package: "@hasna/microservice-agents",
2628
2769
  binary: "microservice-agents",
2629
2770
  schemaPrefix: "agents",
2630
- tags: ["agents", "registry", "orchestration", "routing", "multi-agent", "capabilities", "heartbeat"],
2771
+ tags: [
2772
+ "agents",
2773
+ "registry",
2774
+ "orchestration",
2775
+ "routing",
2776
+ "multi-agent",
2777
+ "capabilities",
2778
+ "heartbeat"
2779
+ ],
2631
2780
  requiredEnv: ["DATABASE_URL"],
2632
2781
  optionalEnv: ["AGENTS_PORT"]
2633
2782
  },
@@ -2639,7 +2788,14 @@ var MICROSERVICES = [
2639
2788
  package: "@hasna/microservice-prompts",
2640
2789
  binary: "microservice-prompts",
2641
2790
  schemaPrefix: "prompts",
2642
- tags: ["prompts", "templates", "versioning", "ab-testing", "overrides", "rollback"],
2791
+ tags: [
2792
+ "prompts",
2793
+ "templates",
2794
+ "versioning",
2795
+ "ab-testing",
2796
+ "overrides",
2797
+ "rollback"
2798
+ ],
2643
2799
  requiredEnv: ["DATABASE_URL"],
2644
2800
  optionalEnv: ["PROMPTS_PORT"]
2645
2801
  }
@@ -2654,24 +2810,43 @@ function searchMicroservices(query) {
2654
2810
  }
2655
2811
 
2656
2812
  // src/lib/installer.ts
2657
- import { execSync, execFileSync } from "child_process";
2658
- function microserviceExists(name) {
2813
+ function getBunGlobalBinDir(env2 = process.env) {
2814
+ const bunInstall = env2.BUN_INSTALL?.trim();
2815
+ if (bunInstall) {
2816
+ return join(bunInstall, "bin");
2817
+ }
2818
+ const home = env2.HOME?.trim();
2819
+ if (!home) {
2820
+ throw new Error("Unable to determine Bun global bin path: HOME is not set.");
2821
+ }
2822
+ return join(home, ".bun", "bin");
2823
+ }
2824
+ function resolveMicroserviceBinary(name) {
2659
2825
  const meta = getMicroservice(name);
2660
2826
  if (!meta)
2661
- return false;
2662
- try {
2663
- execSync(`which ${meta.binary}`, { stdio: "ignore" });
2664
- return true;
2665
- } catch {
2666
- return false;
2827
+ return null;
2828
+ const binDir = getBunGlobalBinDir();
2829
+ const accessMode = process.platform === "win32" ? constants.F_OK : constants.X_OK;
2830
+ const candidates = process.platform === "win32" ? [join(binDir, `${meta.binary}.cmd`), join(binDir, `${meta.binary}.exe`)] : [join(binDir, meta.binary)];
2831
+ for (const candidate of candidates) {
2832
+ try {
2833
+ accessSync(candidate, accessMode);
2834
+ return candidate;
2835
+ } catch {}
2667
2836
  }
2837
+ return null;
2838
+ }
2839
+ function microserviceExists(name) {
2840
+ return resolveMicroserviceBinary(name) !== null;
2668
2841
  }
2669
2842
  function getMicroserviceVersion(name) {
2670
- const meta = getMicroservice(name);
2671
- if (!meta)
2843
+ const binaryPath = resolveMicroserviceBinary(name);
2844
+ if (!binaryPath)
2672
2845
  return null;
2673
2846
  try {
2674
- const out = execFileSync(meta.binary, ["--version"], { encoding: "utf8" }).trim();
2847
+ const out = execFileSync(binaryPath, ["--version"], {
2848
+ encoding: "utf8"
2849
+ }).trim();
2675
2850
  return out || null;
2676
2851
  } catch {
2677
2852
  return null;
@@ -2680,7 +2855,11 @@ function getMicroserviceVersion(name) {
2680
2855
  function installMicroservice(name, options = {}) {
2681
2856
  const meta = getMicroservice(name);
2682
2857
  if (!meta) {
2683
- return { microservice: name, success: false, error: `Unknown microservice '${name}'` };
2858
+ return {
2859
+ microservice: name,
2860
+ success: false,
2861
+ error: `Unknown microservice '${name}'`
2862
+ };
2684
2863
  }
2685
2864
  if (microserviceExists(name) && !options.force) {
2686
2865
  const version = getMicroserviceVersion(name);
@@ -2701,9 +2880,6 @@ function installMicroservice(name, options = {}) {
2701
2880
  function installMicroservices(names, options = {}) {
2702
2881
  return names.map((name) => installMicroservice(name, options));
2703
2882
  }
2704
- function getInstalledMicroservices() {
2705
- return MICROSERVICES.filter((m) => microserviceExists(m.name)).map((m) => m.name);
2706
- }
2707
2883
  function removeMicroservice(name) {
2708
2884
  const meta = getMicroservice(name);
2709
2885
  if (!meta)
@@ -2724,47 +2900,15 @@ function getMicroserviceStatus(name) {
2724
2900
  };
2725
2901
  }
2726
2902
 
2727
- // src/lib/runner.ts
2728
- import { execFile } from "child_process";
2729
- async function runMicroserviceCommand(name, args, timeout = 30000) {
2730
- const meta = getMicroservice(name);
2731
- if (!meta) {
2732
- return { success: false, stdout: "", stderr: `Unknown microservice '${name}'`, exitCode: 1 };
2733
- }
2734
- if (!microserviceExists(name)) {
2735
- return {
2736
- success: false,
2737
- stdout: "",
2738
- stderr: `microservice-${name} is not installed. Run: bun install -g ${meta.package}`,
2739
- exitCode: 1
2740
- };
2741
- }
2742
- return new Promise((resolve) => {
2743
- execFile(meta.binary, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
2744
- if (error && "killed" in error && error.killed) {
2745
- resolve({ success: false, stdout: "", stderr: "Command timed out", exitCode: 1 });
2746
- return;
2747
- }
2748
- const exitCode = error?.code ? typeof error.code === "number" ? error.code : 1 : 0;
2749
- resolve({
2750
- success: exitCode === 0,
2751
- stdout: (stdout || "").trim(),
2752
- stderr: (stderr || "").trim(),
2753
- exitCode
2754
- });
2755
- });
2756
- });
2757
- }
2758
-
2759
2903
  // src/lib/package-info.ts
2760
2904
  import { existsSync, readFileSync } from "fs";
2761
- import { dirname, join, resolve } from "path";
2905
+ import { dirname, join as join2, resolve } from "path";
2762
2906
  import { fileURLToPath } from "url";
2763
2907
  var DEFAULT_VERSION = "0.0.1";
2764
2908
  function findNearestPackageJson(startDir) {
2765
2909
  let dir = resolve(startDir);
2766
2910
  while (true) {
2767
- const candidate = join(dir, "package.json");
2911
+ const candidate = join2(dir, "package.json");
2768
2912
  if (existsSync(candidate)) {
2769
2913
  return candidate;
2770
2914
  }
@@ -2788,6 +2932,57 @@ function getPackageVersion(startDir) {
2788
2932
  return readPackageVersion(packageJsonPath);
2789
2933
  }
2790
2934
 
2935
+ // src/lib/runner.ts
2936
+ import { execFile } from "child_process";
2937
+ async function runMicroserviceCommand(name, args, timeout = 30000) {
2938
+ const meta = getMicroservice(name);
2939
+ if (!meta) {
2940
+ return {
2941
+ success: false,
2942
+ stdout: "",
2943
+ stderr: `Unknown microservice '${name}'`,
2944
+ exitCode: 1
2945
+ };
2946
+ }
2947
+ if (!microserviceExists(name)) {
2948
+ return {
2949
+ success: false,
2950
+ stdout: "",
2951
+ stderr: `${meta.binary} is not installed. Run: bun install -g ${meta.package}`,
2952
+ exitCode: 1
2953
+ };
2954
+ }
2955
+ const binaryPath = resolveMicroserviceBinary(name);
2956
+ if (!binaryPath) {
2957
+ return {
2958
+ success: false,
2959
+ stdout: "",
2960
+ stderr: `Could not resolve global binary for ${meta.binary}.`,
2961
+ exitCode: 1
2962
+ };
2963
+ }
2964
+ return new Promise((resolve2) => {
2965
+ execFile(binaryPath, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (error, stdout, stderr) => {
2966
+ if (error && "killed" in error && error.killed) {
2967
+ resolve2({
2968
+ success: false,
2969
+ stdout: "",
2970
+ stderr: "Command timed out",
2971
+ exitCode: 1
2972
+ });
2973
+ return;
2974
+ }
2975
+ const exitCode = error?.code ? typeof error.code === "number" ? error.code : 1 : 0;
2976
+ resolve2({
2977
+ success: exitCode === 0,
2978
+ stdout: (stdout || "").trim(),
2979
+ stderr: (stderr || "").trim(),
2980
+ exitCode
2981
+ });
2982
+ });
2983
+ });
2984
+ }
2985
+
2791
2986
  // src/cli/index.tsx
2792
2987
  var program2 = new Command;
2793
2988
  program2.name("microservices").description("Production-grade microservice building blocks for SaaS apps").version(getPackageVersion());
@@ -2846,10 +3041,10 @@ Microservice status:
2846
3041
  program2.command("run <name> [args...]").description("Run a command on an installed microservice").action(async (name, args) => {
2847
3042
  const result = await runMicroserviceCommand(name, args);
2848
3043
  if (result.stdout)
2849
- process.stdout.write(result.stdout + `
3044
+ process.stdout.write(`${result.stdout}
2850
3045
  `);
2851
3046
  if (result.stderr)
2852
- process.stderr.write(result.stderr + `
3047
+ process.stderr.write(`${result.stderr}
2853
3048
  `);
2854
3049
  process.exit(result.exitCode);
2855
3050
  });
@@ -2863,25 +3058,130 @@ program2.command("search <query>").description("Search microservices by name or
2863
3058
  console.log(` ${source_default.cyan(m.name.padEnd(20))} ${m.description}`);
2864
3059
  }
2865
3060
  });
2866
- program2.command("migrate-all").description("Run migrations on all installed microservices").option("--db <url>", "PostgreSQL connection URL (overrides DATABASE_URL)").action(async (opts) => {
3061
+ program2.command("migrate-all").description("Run database migrations for all installed microservices").option("--db <url>", "PostgreSQL connection URL (overrides DATABASE_URL)").action(async (opts) => {
3062
+ if (opts.db)
3063
+ process.env.DATABASE_URL = opts.db;
3064
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
3065
+ if (installed.length === 0) {
3066
+ console.log(source_default.yellow("No microservices installed to migrate."));
3067
+ return;
3068
+ }
3069
+ console.log(source_default.bold(`
3070
+ Migrating ${installed.length} installed microservices...
3071
+ `));
3072
+ let hasErrors = false;
3073
+ for (const m of installed) {
3074
+ console.log(source_default.blue(`Migrating ${m.name}...`));
3075
+ const result = await runMicroserviceCommand(m.name, ["migrate"]);
3076
+ if (result.success) {
3077
+ console.log(` ${source_default.green("\u2713")} ${result.stdout.trim() || "Success"}`);
3078
+ } else {
3079
+ console.log(` ${source_default.red("\u2717")} ${result.stderr.trim() || result.stdout.trim() || "Failed"}`);
3080
+ hasErrors = true;
3081
+ }
3082
+ }
3083
+ console.log();
3084
+ if (hasErrors) {
3085
+ console.error(source_default.red("Some migrations failed. Please check the logs above."));
3086
+ process.exit(1);
3087
+ } else {
3088
+ console.log(source_default.green("\u2713 All migrations completed successfully."));
3089
+ }
3090
+ });
3091
+ program2.command("serve-all").description("Start HTTP servers for all installed microservices concurrently").option("--db <url>", "PostgreSQL connection URL (overrides DATABASE_URL)").action(async (opts) => {
2867
3092
  if (opts.db)
2868
- process.env["DATABASE_URL"] = opts.db;
2869
- const installed = getInstalledMicroservices();
3093
+ process.env.DATABASE_URL = opts.db;
3094
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
2870
3095
  if (installed.length === 0) {
2871
- console.log(source_default.yellow("No microservices installed."));
3096
+ console.log(source_default.yellow("No microservices installed to serve."));
2872
3097
  return;
2873
3098
  }
2874
3099
  console.log(source_default.bold(`
2875
- Migrating ${installed.length} microservice(s)...
3100
+ Starting ${installed.length} installed microservices...
2876
3101
  `));
2877
- for (const name of installed) {
2878
- const result = await runMicroserviceCommand(name, ["migrate"]);
2879
- if (result.success)
2880
- console.log(` ${source_default.green("\u2713")} ${name}`);
2881
- else
2882
- console.log(` ${source_default.red("\u2717")} ${name}: ${result.stderr || result.stdout}`);
3102
+ const { spawn } = await import("child_process");
3103
+ const procs = [];
3104
+ const colors = [
3105
+ source_default.cyan,
3106
+ source_default.magenta,
3107
+ source_default.green,
3108
+ source_default.yellow,
3109
+ source_default.blue
3110
+ ];
3111
+ for (let i = 0;i < installed.length; i++) {
3112
+ const m = installed[i];
3113
+ const color = colors[i % colors.length];
3114
+ const prefix = color(`[${m.name.padEnd(10)}] `);
3115
+ const proc = spawn(m.binary, ["serve"], {
3116
+ env: process.env,
3117
+ stdio: ["ignore", "pipe", "pipe"]
3118
+ });
3119
+ proc.stdout.on("data", (data) => {
3120
+ const lines = data.toString().trim().split(`
3121
+ `);
3122
+ for (const line of lines)
3123
+ if (line)
3124
+ console.log(`${prefix}${line}`);
3125
+ });
3126
+ proc.stderr.on("data", (data) => {
3127
+ const lines = data.toString().trim().split(`
3128
+ `);
3129
+ for (const line of lines)
3130
+ if (line)
3131
+ console.error(`${prefix}${source_default.red(line)}`);
3132
+ });
3133
+ proc.on("error", (err) => {
3134
+ console.error(`${prefix}${source_default.red("Failed to start:")} ${err.message}`);
3135
+ });
3136
+ procs.push(proc);
3137
+ }
3138
+ process.on("SIGINT", () => {
3139
+ console.log(source_default.yellow(`
3140
+ Stopping all microservices...`));
3141
+ for (const p of procs)
3142
+ p.kill("SIGINT");
3143
+ process.exit(0);
3144
+ });
3145
+ });
3146
+ program2.command("init-all").description("Run init (migrations) for all installed microservices").option("--db <url>", "PostgreSQL connection URL").action(async (opts) => {
3147
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
3148
+ if (installed.length === 0) {
3149
+ console.log(source_default.yellow("No microservices installed to init."));
3150
+ return;
3151
+ }
3152
+ if (!opts.db) {
3153
+ console.error(source_default.red("--db <url> is required. Example: microservices init-all --db postgres://localhost/myapp"));
3154
+ process.exit(1);
3155
+ }
3156
+ process.env.DATABASE_URL = opts.db;
3157
+ console.log(source_default.bold(`
3158
+ Initializing ${installed.length} installed microservices...
3159
+ `));
3160
+ let hasErrors = false;
3161
+ for (const m of installed) {
3162
+ console.log(source_default.blue(`Initializing ${m.name}...`));
3163
+ const result = await runMicroserviceCommand(m.name, [
3164
+ "init",
3165
+ "--db",
3166
+ opts.db
3167
+ ]);
3168
+ if (result.success) {
3169
+ console.log(` ${source_default.green("\u2713")} ${result.stdout.trim().split(`
3170
+ `).join(`
3171
+ `) || "Success"}`);
3172
+ } else {
3173
+ console.log(` ${source_default.red("\u2717")} ${result.stderr.trim() || result.stdout.trim() || "Failed"}`);
3174
+ hasErrors = true;
3175
+ }
2883
3176
  }
2884
3177
  console.log();
3178
+ if (hasErrors) {
3179
+ console.error(source_default.red("Some inits failed. Please check the logs above."));
3180
+ process.exit(1);
3181
+ } else {
3182
+ console.log(source_default.green("\u2713 All services initialized successfully."));
3183
+ console.log(source_default.gray(" You can now run 'microservices serve-all' to start them."));
3184
+ }
2885
3185
  });
2886
3186
  program2.command("info <name>").description("Show detailed info about a microservice").action((name) => {
2887
3187
  const m = getMicroservice(name);
@@ -2904,4 +3204,89 @@ ${m.displayName}`));
2904
3204
  console.log(` Tags: ${m.tags.join(", ")}`);
2905
3205
  console.log();
2906
3206
  });
3207
+ program2.command("check-env").description("Verify environment variables for all installed microservices").action(() => {
3208
+ const installed = MICROSERVICES.filter((m) => microserviceExists(m.name));
3209
+ if (installed.length === 0) {
3210
+ console.log(source_default.yellow("No microservices installed to check."));
3211
+ return;
3212
+ }
3213
+ console.log(source_default.bold(`
3214
+ Checking environment for ${installed.length} microservices...
3215
+ `));
3216
+ let totalMissing = 0;
3217
+ for (const m of installed) {
3218
+ const missingRequired = m.requiredEnv.filter((env2) => !process.env[env2]);
3219
+ const missingOptional = (m.optionalEnv ?? []).filter((env2) => !process.env[env2]);
3220
+ const status = missingRequired.length > 0 ? source_default.red("\u2717 Critical Missing") : missingOptional.length > 0 ? source_default.yellow("\u26A0 Warning") : source_default.green("\u2713 OK");
3221
+ console.log(`${source_default.bold(m.name.padEnd(12))} [${status}]`);
3222
+ if (missingRequired.length > 0) {
3223
+ console.log(source_default.red(` Required missing: ${missingRequired.join(", ")}`));
3224
+ totalMissing += missingRequired.length;
3225
+ }
3226
+ if (missingOptional.length > 0) {
3227
+ console.log(source_default.gray(` Optional missing: ${missingOptional.join(", ")}`));
3228
+ }
3229
+ if (missingRequired.length === 0 && missingOptional.length === 0) {
3230
+ console.log(source_default.gray(" All variables set."));
3231
+ }
3232
+ console.log();
3233
+ }
3234
+ if (totalMissing > 0) {
3235
+ console.log(source_default.red(`Found ${totalMissing} missing required environment variables.`));
3236
+ console.log(source_default.gray(`Refer to .env.example for guidance.
3237
+ `));
3238
+ process.exit(1);
3239
+ } else {
3240
+ console.log(source_default.green(`\u2713 All required environment variables are set across all installed services.
3241
+ `));
3242
+ }
3243
+ });
3244
+ program2.command("scaffold <name>").description("Scaffold a new microservice from the _template directory").action((name) => {
3245
+ if (!/^[a-z0-9-]+$/.test(name)) {
3246
+ console.error(source_default.red("Error: Name can only contain lowercase letters, numbers, and dashes."));
3247
+ process.exit(1);
3248
+ }
3249
+ const cwd = process.cwd();
3250
+ const templateDir = path.join(cwd, "microservices", "_template");
3251
+ const targetDir = path.join(cwd, "microservices", `microservice-${name}`);
3252
+ if (!fs.existsSync(templateDir)) {
3253
+ console.error(source_default.red(`Template directory not found at ${templateDir}. Make sure you are running this from the monorepo root.`));
3254
+ process.exit(1);
3255
+ }
3256
+ if (fs.existsSync(targetDir)) {
3257
+ console.error(source_default.red(`Target directory already exists at ${targetDir}`));
3258
+ process.exit(1);
3259
+ }
3260
+ console.log(source_default.bold(`
3261
+ Scaffolding microservice-${name}...
3262
+ `));
3263
+ fs.cpSync(templateDir, targetDir, { recursive: true });
3264
+ const replaceInFile = (filePath) => {
3265
+ const content = fs.readFileSync(filePath, "utf-8");
3266
+ let updated = content.replace(/__NAME__/g, name.toUpperCase().replace(/-/g, "_"));
3267
+ updated = updated.replace(/__Name__/g, name.charAt(0).toUpperCase() + name.slice(1));
3268
+ updated = updated.replace(/__name__/g, name);
3269
+ fs.writeFileSync(filePath, updated, "utf-8");
3270
+ };
3271
+ const walkAndReplace = (dir) => {
3272
+ const files = fs.readdirSync(dir);
3273
+ for (const file of files) {
3274
+ const filePath = path.join(dir, file);
3275
+ if (fs.statSync(filePath).isDirectory()) {
3276
+ walkAndReplace(filePath);
3277
+ } else {
3278
+ replaceInFile(filePath);
3279
+ }
3280
+ }
3281
+ };
3282
+ walkAndReplace(targetDir);
3283
+ console.log(` ${source_default.green("\u2713")} Created microservices/microservice-${name}`);
3284
+ console.log(source_default.gray(`
3285
+ Next steps:
3286
+ 1. Add entry to src/lib/registry.ts
3287
+ 2. Implement schema, core logic, HTTP API, MCP, and CLI
3288
+ 3. Run 'bun install' to link the workspace
3289
+ 4. Run 'bun run build'
3290
+ `));
3291
+ });
2907
3292
  program2.parse();