@uxmaltech/collab-cli 0.1.0 → 0.1.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.
@@ -12,6 +12,7 @@ const config_1 = require("../lib/config");
12
12
  const ecosystem_1 = require("../lib/ecosystem");
13
13
  const compose_renderer_1 = require("../lib/compose-renderer");
14
14
  const errors_1 = require("../lib/errors");
15
+ const infra_type_1 = require("../lib/infra-type");
15
16
  const mode_1 = require("../lib/mode");
16
17
  const parsers_1 = require("../lib/parsers");
17
18
  const orchestrator_1 = require("../lib/orchestrator");
@@ -52,19 +53,32 @@ function inferComposeMode(config) {
52
53
  }
53
54
  return 'consolidated';
54
55
  }
55
- async function resolveWizardSelection(options, config) {
56
+ async function resolveWizardSelection(options, config, logger) {
56
57
  const defaults = {
57
58
  mode: (0, mode_1.parseMode)(options.mode, config.mode),
58
59
  composeMode: parseComposeMode(options.composeMode, inferComposeMode(config)),
60
+ infraType: (0, infra_type_1.parseInfraType)(options.infraType, config.infraType),
59
61
  };
60
62
  if (options.yes) {
61
63
  if (!options.mode) {
62
64
  process.stderr.write('Info: Non-interactive mode defaults to file-only. Use --mode indexed for graph/vector features.\n');
63
65
  }
66
+ const mode = options.mode ? (0, mode_1.parseMode)(options.mode) : 'file-only';
67
+ const infraType = mode === 'indexed'
68
+ ? (0, infra_type_1.parseInfraType)(options.infraType, 'local')
69
+ : 'local';
70
+ let mcpUrl;
71
+ if (infraType === 'remote') {
72
+ if (!options.mcpUrl) {
73
+ throw new errors_1.CliError('--mcp-url is required with --infra-type remote in non-interactive mode.');
74
+ }
75
+ mcpUrl = (0, infra_type_1.validateMcpUrl)(options.mcpUrl);
76
+ }
64
77
  return {
65
- ...defaults,
66
- mode: options.mode ? (0, mode_1.parseMode)(options.mode) : 'file-only',
78
+ mode,
67
79
  composeMode: options.composeMode ? parseComposeMode(options.composeMode) : 'consolidated',
80
+ infraType,
81
+ mcpUrl,
68
82
  };
69
83
  }
70
84
  const mode = options.mode
@@ -73,9 +87,26 @@ async function resolveWizardSelection(options, config) {
73
87
  { value: 'file-only', label: 'file-only (skip infra + MCP startup)' },
74
88
  { value: 'indexed', label: 'indexed (start infra + MCP and enable retrieval)' },
75
89
  ], defaults.mode);
76
- // Skip compose-mode prompt when mode is file-only — no Docker/MCP
77
- // infrastructure is used, so compose configuration is irrelevant.
78
- const composeMode = mode === 'file-only'
90
+ // ── Indexed-only: infrastructure type selection ─────────────
91
+ let infraType = 'local';
92
+ let mcpUrl;
93
+ if (mode === 'indexed') {
94
+ logger.phaseHeader('collab init', 'Infrastructure');
95
+ infraType = options.infraType
96
+ ? (0, infra_type_1.parseInfraType)(options.infraType)
97
+ : await (0, prompt_1.promptChoice)('Infrastructure type:', [
98
+ { value: 'local', label: 'local (Docker Compose)' },
99
+ { value: 'remote', label: 'remote (connect to existing MCP server)' },
100
+ ], defaults.infraType);
101
+ if (infraType === 'remote') {
102
+ const rawUrl = options.mcpUrl
103
+ ?? await (0, prompt_1.promptText)('MCP server base URL:', 'http://127.0.0.1:7337');
104
+ mcpUrl = (0, infra_type_1.validateMcpUrl)(rawUrl);
105
+ }
106
+ }
107
+ // Skip compose-mode prompt when mode is file-only or infra is remote —
108
+ // Docker Compose configuration is only relevant for local infrastructure.
109
+ const composeMode = mode === 'file-only' || infraType === 'remote'
79
110
  ? parseComposeMode(options.composeMode, 'consolidated')
80
111
  : options.composeMode
81
112
  ? parseComposeMode(options.composeMode)
@@ -86,11 +117,15 @@ async function resolveWizardSelection(options, config) {
86
117
  return {
87
118
  mode,
88
119
  composeMode,
120
+ infraType,
121
+ mcpUrl,
89
122
  };
90
123
  }
91
124
  function renderMcpSnippet(provider, config) {
92
125
  const workspace = config.workspaceDir;
93
- const mcpUrl = 'http://127.0.0.1:7337/mcp';
126
+ const mcpUrl = config.mcpUrl
127
+ ? `${config.mcpUrl}/mcp`
128
+ : 'http://127.0.0.1:7337/mcp';
94
129
  switch (provider) {
95
130
  case 'codex':
96
131
  return {
@@ -422,6 +457,70 @@ function buildInfraStages(effectiveConfig, executor, logger, options, composeMod
422
457
  ];
423
458
  }
424
459
  // ────────────────────────────────────────────────────────────────
460
+ // Remote infra stages (no Docker — connect to existing MCP)
461
+ // ────────────────────────────────────────────────────────────────
462
+ function buildRemoteInfraStages(effectiveConfig, executor, logger, options, mcpUrl) {
463
+ const health = (0, service_health_1.dryRunHealthOptions)(executor, {
464
+ timeoutMs: (0, parsers_1.parseNumber)(options.timeoutMs, 5_000),
465
+ retries: (0, parsers_1.parseNumber)(options.retries, 15),
466
+ retryDelayMs: (0, parsers_1.parseNumber)(options.retryDelayMs, 2_000),
467
+ });
468
+ return [
469
+ {
470
+ id: 'mcp-health-check',
471
+ title: 'Verify remote MCP service health',
472
+ recovery: [
473
+ 'Check that the remote MCP server is running and accessible.',
474
+ 'Verify the --mcp-url value points to a healthy MCP endpoint.',
475
+ 'Run collab init --resume after fixing remote connectivity.',
476
+ ],
477
+ run: async () => {
478
+ const parsed = new URL(mcpUrl);
479
+ const env = {
480
+ MCP_HOST: parsed.hostname,
481
+ MCP_PORT: parsed.port || (parsed.protocol === 'https:' ? '443' : '80'),
482
+ };
483
+ const probe = await (0, service_health_1.waitForMcpHealth)(env, health);
484
+ if (!probe.ok) {
485
+ throw new errors_1.CliError(`Remote MCP is not healthy at ${mcpUrl}: ${probe.errors.join(', ')}`);
486
+ }
487
+ (0, service_health_1.logServiceHealth)(logger, 'remote MCP health', probe);
488
+ },
489
+ },
490
+ {
491
+ id: 'mcp-client-config',
492
+ title: 'Generate MCP client config snippets',
493
+ recovery: [
494
+ 'Verify permissions in .collab directory.',
495
+ 'Run collab init --resume to regenerate MCP config snippets.',
496
+ ],
497
+ run: () => {
498
+ if (options.skipMcpSnippets) {
499
+ logger.info('Skipping MCP snippet generation by user choice.');
500
+ return;
501
+ }
502
+ const enabled = (0, providers_1.getEnabledProviders)(effectiveConfig);
503
+ if (enabled.length === 0) {
504
+ logger.info('No providers configured; skipping MCP snippet generation.');
505
+ return;
506
+ }
507
+ for (const provider of enabled) {
508
+ const snippet = renderMcpSnippet(provider, effectiveConfig);
509
+ if (!snippet)
510
+ continue;
511
+ const target = node_path_1.default.join(effectiveConfig.collabDir, snippet.filename);
512
+ executor.writeFile(target, snippet.content, {
513
+ description: `write ${providers_1.PROVIDER_DEFAULTS[provider].label} MCP config snippet`,
514
+ });
515
+ }
516
+ logger.info(`Generated MCP snippets for: ${enabled.map((k) => providers_1.PROVIDER_DEFAULTS[k].label).join(', ')}`);
517
+ },
518
+ },
519
+ graph_seed_1.graphSeedStage,
520
+ canon_ingest_1.canonIngestStage,
521
+ ];
522
+ }
523
+ // ────────────────────────────────────────────────────────────────
425
524
  // File-only pipeline (8 stages)
426
525
  // ────────────────────────────────────────────────────────────────
427
526
  function buildFileOnlyPipeline(effectiveConfig, executor, logger, configExistedBefore, options) {
@@ -440,20 +539,23 @@ function buildFileOnlyPipeline(effectiveConfig, executor, logger, configExistedB
440
539
  // ────────────────────────────────────────────────────────────────
441
540
  // Indexed pipeline (15 stages)
442
541
  // ────────────────────────────────────────────────────────────────
443
- function buildIndexedPipeline(effectiveConfig, executor, logger, configExistedBefore, options, composeMode) {
542
+ function buildIndexedPipeline(effectiveConfig, executor, logger, configExistedBefore, options, composeMode, infraType = 'local', mcpUrl) {
543
+ const infraStages = infraType === 'remote' && mcpUrl
544
+ ? buildRemoteInfraStages(effectiveConfig, executor, logger, options, mcpUrl)
545
+ : buildInfraStages(effectiveConfig, executor, logger, options, composeMode);
444
546
  return [
445
547
  // Phase A — Local setup (shared with file-only)
446
- buildPreflightStage(executor, logger, 'indexed'), // 1
447
- buildConfigStage(effectiveConfig, executor, logger, configExistedBefore, options.force), // 2
448
- buildGitHubAuthStage(effectiveConfig, logger, options), // 3
449
- assistant_setup_1.assistantSetupStage, // 4
450
- canon_sync_1.canonSyncStage, // 5
451
- repo_scaffold_1.repoScaffoldStage, // 6
452
- repo_analysis_1.repoAnalysisStage, // 7
453
- ci_setup_1.ciSetupStage, // 8
454
- agent_skills_setup_1.agentSkillsSetupStage, // 9
455
- // Phase B — Infrastructure + Phase C — Ingestion (9-14)
456
- ...buildInfraStages(effectiveConfig, executor, logger, options, composeMode),
548
+ buildPreflightStage(executor, logger, infraType === 'local' ? 'indexed' : undefined),
549
+ buildConfigStage(effectiveConfig, executor, logger, configExistedBefore, options.force),
550
+ buildGitHubAuthStage(effectiveConfig, logger, options),
551
+ assistant_setup_1.assistantSetupStage,
552
+ canon_sync_1.canonSyncStage,
553
+ repo_scaffold_1.repoScaffoldStage,
554
+ repo_analysis_1.repoAnalysisStage,
555
+ ci_setup_1.ciSetupStage,
556
+ agent_skills_setup_1.agentSkillsSetupStage,
557
+ // Phase B — Infrastructure + Phase C — Ingestion
558
+ ...infraStages,
457
559
  ];
458
560
  }
459
561
  // ────────────────────────────────────────────────────────────────
@@ -473,26 +575,45 @@ async function runInfraOnly(context, options) {
473
575
  context.executor.ensureDirectory(effectiveConfig.collabDir);
474
576
  context.executor.writeFile(effectiveConfig.configFile, `${(0, config_1.serializeUserConfig)(effectiveConfig)}\n`, { description: 'write collab config (infra bootstrap)' });
475
577
  }
578
+ const infraType = (0, infra_type_1.parseInfraType)(options.infraType, effectiveConfig.infraType);
579
+ let mcpUrl;
580
+ if (infraType === 'remote') {
581
+ if (!options.mcpUrl && !effectiveConfig.mcpUrl) {
582
+ throw new errors_1.CliError('--mcp-url is required for remote infrastructure.');
583
+ }
584
+ mcpUrl = options.mcpUrl ? (0, infra_type_1.validateMcpUrl)(options.mcpUrl) : effectiveConfig.mcpUrl;
585
+ effectiveConfig.infraType = infraType;
586
+ effectiveConfig.mcpUrl = mcpUrl;
587
+ }
476
588
  const composeMode = parseComposeMode(options.composeMode, inferComposeMode(effectiveConfig));
477
- context.logger.phaseHeader('Infrastructure', 'Docker + MCP services');
478
- const infraStages = buildInfraStages(effectiveConfig, context.executor, context.logger, options, composeMode);
589
+ const infraLabel = infraType === 'remote' ? 'Remote MCP services' : 'Docker + MCP services';
590
+ context.logger.phaseHeader('Infrastructure', infraLabel);
591
+ const infraStages = infraType === 'remote' && mcpUrl
592
+ ? buildRemoteInfraStages(effectiveConfig, context.executor, context.logger, options, mcpUrl)
593
+ : buildInfraStages(effectiveConfig, context.executor, context.logger, options, composeMode);
479
594
  await (0, orchestrator_1.runOrchestration)({
480
595
  workflowId: 'init:infra',
481
596
  config: effectiveConfig,
482
597
  executor: context.executor,
483
598
  logger: context.logger,
484
599
  resume: options.resume,
485
- mode: 'indexed (infra)',
600
+ mode: `indexed (infra ${infraType})`,
486
601
  stageOptions: { outputDir: options.outputDir },
487
602
  }, infraStages);
488
603
  // Summary
489
604
  context.logger.phaseHeader('Infrastructure Ready');
490
- context.logger.summaryFooter([
491
- { label: 'Phase', value: 'infra only' },
492
- { label: 'Compose mode', value: composeMode },
605
+ const summaryEntries = [
606
+ { label: 'Phase', value: `infra ${infraType}` },
493
607
  { label: 'Dry-run', value: context.executor.dryRun ? 'yes' : 'no' },
494
608
  { label: 'Config', value: effectiveConfig.configFile },
495
- ]);
609
+ ];
610
+ if (infraType === 'remote' && mcpUrl) {
611
+ summaryEntries.splice(1, 0, { label: 'MCP URL', value: mcpUrl });
612
+ }
613
+ else {
614
+ summaryEntries.splice(1, 0, { label: 'Compose mode', value: composeMode });
615
+ }
616
+ context.logger.summaryFooter(summaryEntries);
496
617
  }
497
618
  // ────────────────────────────────────────────────────────────────
498
619
  // Repo domain generation (collab init --repo=<package>)
@@ -626,6 +747,8 @@ function registerInitCommand(program) {
626
747
  .option('--resume', 'Resume from the last incomplete wizard stage')
627
748
  .option('--mode <mode>', 'Wizard mode: file-only|indexed')
628
749
  .option('--compose-mode <mode>', 'Compose mode: consolidated|split')
750
+ .option('--infra-type <type>', 'Infrastructure type: local|remote (indexed mode only)')
751
+ .option('--mcp-url <url>', 'MCP server base URL for remote infrastructure')
629
752
  .option('--output-dir <directory>', 'Directory used to write compose outputs')
630
753
  .option('--repos <list>', 'Comma-separated repo directories for workspace mode')
631
754
  .option('--repo <package>', 'Generate domain definition from package analysis')
@@ -647,6 +770,7 @@ Examples:
647
770
  collab init --repos api,web,shared --yes
648
771
  collab init --repo collab-chat-ai-pkg --mode file-only
649
772
  collab init --repo collab-chat-ai-pkg --mode indexed
773
+ collab init --yes --mode indexed --infra-type remote --mcp-url http://my-server:7337 --business-canon none
650
774
  collab init --resume
651
775
  collab init infra
652
776
  collab init infra --resume
@@ -684,12 +808,14 @@ Examples:
684
808
  }
685
809
  // ── Step 1: Configuration wizard ────────────────────────
686
810
  context.logger.phaseHeader('collab init', 'Configuration');
687
- const selections = await resolveWizardSelection(options, context.config);
811
+ const selections = await resolveWizardSelection(options, context.config, context.logger);
688
812
  const preserveExisting = configExistedBefore && !options.force;
689
813
  const effectiveConfig = {
690
814
  ...(0, config_1.defaultCollabConfig)(context.config.workspaceDir),
691
815
  ...context.config,
692
816
  mode: preserveExisting ? context.config.mode : selections.mode,
817
+ infraType: preserveExisting ? context.config.infraType : selections.infraType,
818
+ mcpUrl: preserveExisting ? context.config.mcpUrl : selections.mcpUrl,
693
819
  };
694
820
  // ── Step 2: Business canon configuration ──────────────────
695
821
  const canons = await resolveBusinessCanon(options, context.logger);
@@ -745,8 +871,13 @@ Examples:
745
871
  }
746
872
  // Phase I — infra stages (indexed only)
747
873
  if (selections.mode === 'indexed') {
748
- context.logger.phaseHeader('Infrastructure', 'Docker + MCP services');
749
- const infraStages = buildInfraStages(effectiveConfig, context.executor, context.logger, options, selections.composeMode);
874
+ const infraLabel = selections.infraType === 'remote'
875
+ ? 'Remote MCP services'
876
+ : 'Docker + MCP services';
877
+ context.logger.phaseHeader('Infrastructure', infraLabel);
878
+ const infraStages = selections.infraType === 'remote' && selections.mcpUrl
879
+ ? buildRemoteInfraStages(effectiveConfig, context.executor, context.logger, options, selections.mcpUrl)
880
+ : buildInfraStages(effectiveConfig, context.executor, context.logger, options, selections.composeMode);
750
881
  await (0, orchestrator_1.runOrchestration)({
751
882
  workflowId: 'init:infra',
752
883
  config: effectiveConfig,
@@ -763,7 +894,7 @@ Examples:
763
894
  context.logger.phaseHeader('Project Setup', selections.mode);
764
895
  const stages = selections.mode === 'file-only'
765
896
  ? buildFileOnlyPipeline(effectiveConfig, context.executor, context.logger, configExistedBefore, options)
766
- : buildIndexedPipeline(effectiveConfig, context.executor, context.logger, configExistedBefore, options, selections.composeMode);
897
+ : buildIndexedPipeline(effectiveConfig, context.executor, context.logger, configExistedBefore, options, selections.composeMode, selections.infraType, selections.mcpUrl);
767
898
  await (0, orchestrator_1.runOrchestration)({
768
899
  workflowId: 'init',
769
900
  config: effectiveConfig,
@@ -790,7 +921,13 @@ Examples:
790
921
  summaryEntries.splice(1, 0, { label: 'Workspace', value: `${ws.name} (${ws.type})` }, { label: 'Repos', value: ws.repos.join(', ') });
791
922
  }
792
923
  if (selections.mode === 'indexed') {
793
- summaryEntries.splice(ws ? 3 : 1, 0, { label: 'Compose mode', value: selections.composeMode });
924
+ summaryEntries.push({ label: 'Infrastructure', value: selections.infraType });
925
+ if (selections.infraType === 'remote' && selections.mcpUrl) {
926
+ summaryEntries.push({ label: 'MCP URL', value: selections.mcpUrl });
927
+ }
928
+ else {
929
+ summaryEntries.push({ label: 'Compose mode', value: selections.composeMode });
930
+ }
794
931
  }
795
932
  context.logger.summaryFooter(summaryEntries);
796
933
  // Ecosystem compatibility checks
@@ -15,6 +15,7 @@ exports.deriveWorkspaceName = deriveWorkspaceName;
15
15
  exports.detectWorkspaceLayout = detectWorkspaceLayout;
16
16
  const node_fs_1 = __importDefault(require("node:fs"));
17
17
  const node_path_1 = __importDefault(require("node:path"));
18
+ const infra_type_1 = require("./infra-type");
18
19
  const mode_1 = require("./mode");
19
20
  const DEFAULT_COMPOSE_PATHS = {
20
21
  consolidatedFile: 'docker-compose.yml',
@@ -32,6 +33,7 @@ function defaultCollabConfig(cwd = process.cwd()) {
32
33
  stateFile: node_path_1.default.join(collabDir, 'state.json'),
33
34
  envFile: node_path_1.default.join(workspaceDir, '.env'),
34
35
  mode: mode_1.DEFAULT_MODE,
36
+ infraType: infra_type_1.DEFAULT_INFRA_TYPE,
35
37
  compose: { ...DEFAULT_COMPOSE_PATHS },
36
38
  architectureDir,
37
39
  uxmaltechDir: node_path_1.default.join(architectureDir, 'uxmaltech'),
@@ -54,9 +56,12 @@ function loadCollabConfig(cwd = process.cwd()) {
54
56
  ? node_path_1.default.resolve(defaults.workspaceDir, raw.architectureDir)
55
57
  : defaults.architectureDir;
56
58
  const workspace = migrateWorkspaceConfig(raw.workspace, defaults.workspaceDir);
59
+ const infraType = (0, infra_type_1.parseInfraType)(raw.infraType, defaults.infraType);
57
60
  return {
58
61
  ...defaults,
59
62
  mode: (0, mode_1.parseMode)(raw.mode, defaults.mode),
63
+ infraType,
64
+ mcpUrl: infraType === 'remote' && raw.mcpUrl ? raw.mcpUrl : undefined,
60
65
  envFile: raw.envFile ? node_path_1.default.resolve(defaults.workspaceDir, raw.envFile) : defaults.envFile,
61
66
  compose: {
62
67
  consolidatedFile: raw.compose?.consolidatedFile ?? defaults.compose.consolidatedFile,
@@ -82,6 +87,13 @@ function serializeUserConfig(config) {
82
87
  compose: config.compose,
83
88
  envFile: node_path_1.default.relative(config.workspaceDir, config.envFile),
84
89
  };
90
+ // Only persist infraType when it differs from the default (local).
91
+ if (config.infraType && config.infraType !== 'local') {
92
+ data.infraType = config.infraType;
93
+ }
94
+ if (config.mcpUrl) {
95
+ data.mcpUrl = config.mcpUrl;
96
+ }
85
97
  if (config.assistants) {
86
98
  data.assistants = config.assistants;
87
99
  }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_INFRA_TYPE = exports.INFRA_TYPES = void 0;
4
+ exports.isInfraType = isInfraType;
5
+ exports.parseInfraType = parseInfraType;
6
+ exports.validateMcpUrl = validateMcpUrl;
7
+ const errors_1 = require("./errors");
8
+ /** Supported infrastructure types for indexed mode. */
9
+ exports.INFRA_TYPES = ['local', 'remote'];
10
+ const INFRA_SET = new Set(exports.INFRA_TYPES);
11
+ /** Default infra type used when none is explicitly configured. */
12
+ exports.DEFAULT_INFRA_TYPE = 'local';
13
+ /** Type guard that checks whether a string is a valid {@link InfraType}. */
14
+ function isInfraType(value) {
15
+ return INFRA_SET.has(value);
16
+ }
17
+ /**
18
+ * Parses an infra-type string from CLI flags or config, returning the fallback
19
+ * when undefined. Throws on invalid values.
20
+ */
21
+ function parseInfraType(value, fallback = exports.DEFAULT_INFRA_TYPE) {
22
+ if (value === undefined) {
23
+ return fallback;
24
+ }
25
+ if (isInfraType(value)) {
26
+ return value;
27
+ }
28
+ throw new errors_1.CliError(`Invalid infra type '${value}'. Valid values: ${exports.INFRA_TYPES.join(', ')}`);
29
+ }
30
+ /**
31
+ * Validates and normalises an MCP base URL.
32
+ *
33
+ * - Must start with `http://` or `https://`.
34
+ * - Must be parseable by the URL constructor.
35
+ * - Trailing slashes are stripped from the origin.
36
+ *
37
+ * @returns The normalised base URL (e.g. `http://my-server:7337`).
38
+ */
39
+ function validateMcpUrl(url) {
40
+ const trimmed = url.trim();
41
+ if (!trimmed) {
42
+ throw new errors_1.CliError('MCP URL cannot be empty.');
43
+ }
44
+ if (!/^https?:\/\//i.test(trimmed)) {
45
+ throw new errors_1.CliError(`MCP URL must start with http:// or https://. Got: ${trimmed}`);
46
+ }
47
+ let parsed;
48
+ try {
49
+ parsed = new URL(trimmed);
50
+ }
51
+ catch {
52
+ throw new errors_1.CliError(`Invalid MCP URL: ${trimmed}`);
53
+ }
54
+ // Return origin (scheme + host + port) without trailing path/slash
55
+ return parsed.origin;
56
+ }
@@ -48,6 +48,11 @@ function resolveMcpApiKey(env) {
48
48
  return firstFromList || undefined;
49
49
  }
50
50
  function getMcpBaseUrl(config) {
51
+ // Remote infra: use the explicitly configured URL.
52
+ if (config.mcpUrl) {
53
+ return config.mcpUrl;
54
+ }
55
+ // Local infra: derive from .env or defaults.
51
56
  const env = (0, service_health_1.loadRuntimeEnv)(config);
52
57
  const host = env.MCP_HOST || '127.0.0.1';
53
58
  const port = env.MCP_PORT || '7337';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxmaltech/collab-cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "CLI for collaborative architecture and delivery workflows.",
5
5
  "private": false,
6
6
  "license": "UNLICENSED",