@cortex-context/cli 0.0.5 → 0.0.6

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/index.js CHANGED
@@ -5617,7 +5617,7 @@ var require_dist = __commonJS({
5617
5617
  });
5618
5618
  };
5619
5619
  }
5620
- var prompts3 = require_prompts();
5620
+ var prompts5 = require_prompts();
5621
5621
  var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
5622
5622
  var noop = () => {
5623
5623
  };
@@ -5668,7 +5668,7 @@ var require_dist = __commonJS({
5668
5668
  var _question2 = question;
5669
5669
  name = _question2.name;
5670
5670
  type = _question2.type;
5671
- if (prompts3[type] === void 0) {
5671
+ if (prompts5[type] === void 0) {
5672
5672
  throw new Error(`prompt type (${type}) is not defined`);
5673
5673
  }
5674
5674
  if (override2[question.name] !== void 0) {
@@ -5679,7 +5679,7 @@ var require_dist = __commonJS({
5679
5679
  }
5680
5680
  }
5681
5681
  try {
5682
- answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts3[type](question);
5682
+ answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts5[type](question);
5683
5683
  answers[name] = answer = yield getFormattedAnswer(question, answer, true);
5684
5684
  quit = yield onSubmit(question, answer, answers);
5685
5685
  } catch (err) {
@@ -5711,7 +5711,7 @@ var require_dist = __commonJS({
5711
5711
  }
5712
5712
  module2.exports = Object.assign(prompt, {
5713
5713
  prompt,
5714
- prompts: prompts3,
5714
+ prompts: prompts5,
5715
5715
  inject,
5716
5716
  override
5717
5717
  });
@@ -7798,7 +7798,7 @@ var require_prompts2 = __commonJS({
7798
7798
  var require_lib = __commonJS({
7799
7799
  "node_modules/prompts/lib/index.js"(exports2, module2) {
7800
7800
  "use strict";
7801
- var prompts3 = require_prompts2();
7801
+ var prompts5 = require_prompts2();
7802
7802
  var passOn = ["suggest", "format", "onState", "validate", "onRender", "type"];
7803
7803
  var noop = () => {
7804
7804
  };
@@ -7830,7 +7830,7 @@ var require_lib = __commonJS({
7830
7830
  throw new Error("prompt message is required");
7831
7831
  }
7832
7832
  ({ name, type } = question);
7833
- if (prompts3[type] === void 0) {
7833
+ if (prompts5[type] === void 0) {
7834
7834
  throw new Error(`prompt type (${type}) is not defined`);
7835
7835
  }
7836
7836
  if (override2[question.name] !== void 0) {
@@ -7841,7 +7841,7 @@ var require_lib = __commonJS({
7841
7841
  }
7842
7842
  }
7843
7843
  try {
7844
- answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts3[type](question);
7844
+ answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts5[type](question);
7845
7845
  answers[name] = answer = await getFormattedAnswer(question, answer, true);
7846
7846
  quit = await onSubmit(question, answer, answers);
7847
7847
  } catch (err) {
@@ -7864,7 +7864,7 @@ var require_lib = __commonJS({
7864
7864
  function override(answers) {
7865
7865
  prompt._override = Object.assign({}, answers);
7866
7866
  }
7867
- module2.exports = Object.assign(prompt, { prompt, prompts: prompts3, inject, override });
7867
+ module2.exports = Object.assign(prompt, { prompt, prompts: prompts5, inject, override });
7868
7868
  }
7869
7869
  });
7870
7870
 
@@ -16901,7 +16901,7 @@ var source_default = chalk;
16901
16901
  // src/commands/init.ts
16902
16902
  var import_path8 = require("path");
16903
16903
  var import_fs8 = require("fs");
16904
- var import_prompts = __toESM(require_prompts3());
16904
+ var import_prompts2 = __toESM(require_prompts3());
16905
16905
 
16906
16906
  // node_modules/ora/index.js
16907
16907
  var import_node_process7 = __toESM(require("process"), 1);
@@ -17840,7 +17840,10 @@ function writeConfig(config2) {
17840
17840
  (0, import_fs.mkdirSync)(CONFIG_DIR, { recursive: true });
17841
17841
  }
17842
17842
  const current = readConfig();
17843
- (0, import_fs.writeFileSync)(CONFIG_FILE, JSON.stringify({ ...current, ...config2 }, null, 2));
17843
+ (0, import_fs.writeFileSync)(
17844
+ CONFIG_FILE,
17845
+ JSON.stringify({ ...current, ...config2 }, null, 2)
17846
+ );
17844
17847
  }
17845
17848
  function deleteConfig() {
17846
17849
  if ((0, import_fs.existsSync)(CONFIG_FILE)) {
@@ -17944,11 +17947,56 @@ function printInstallResult(label, result, dryRun) {
17944
17947
  var import_fs3 = require("fs");
17945
17948
  var import_path3 = require("path");
17946
17949
  var import_os2 = require("os");
17947
- function getMcpConfigPath(workspacePath) {
17948
- return (0, import_path3.join)(workspacePath, ".vscode", "mcp.json");
17950
+ var import_prompts = __toESM(require_prompts3());
17951
+ async function detectWorkspaceTarget(workspacePath) {
17952
+ const hasVscode = (0, import_fs3.existsSync)((0, import_path3.join)(workspacePath, ".vscode"));
17953
+ const hasCursor = (0, import_fs3.existsSync)((0, import_path3.join)(workspacePath, ".cursor"));
17954
+ const hasClaude = (0, import_fs3.existsSync)((0, import_path3.join)(workspacePath, ".claude"));
17955
+ if (hasVscode) {
17956
+ return {
17957
+ target: "vscode",
17958
+ mcpPath: (0, import_path3.join)(workspacePath, ".vscode", "mcp.json"),
17959
+ isFallback: false
17960
+ };
17961
+ }
17962
+ if (hasCursor) {
17963
+ return {
17964
+ target: "cursor",
17965
+ mcpPath: (0, import_path3.join)(workspacePath, ".cursor", "mcp.json"),
17966
+ isFallback: false
17967
+ };
17968
+ }
17969
+ if (hasClaude) {
17970
+ return {
17971
+ target: "claude",
17972
+ mcpPath: (0, import_path3.join)(workspacePath, ".claude", "mcp.json"),
17973
+ isFallback: false
17974
+ };
17975
+ }
17976
+ console.log(
17977
+ source_default.yellow(
17978
+ " \u26A0 No IDE workspace detected (.vscode/, .cursor/, .claude/)"
17979
+ )
17980
+ );
17981
+ console.log(
17982
+ source_default.dim(
17983
+ " .agents/ is the emerging standard for IDE-agnostic AI config."
17984
+ )
17985
+ );
17986
+ const { confirm } = await (0, import_prompts.default)({
17987
+ type: "confirm",
17988
+ name: "confirm",
17989
+ message: "Install MCP config into .agents/mcp.json?",
17990
+ initial: true
17991
+ });
17992
+ if (!confirm) return null;
17993
+ return {
17994
+ target: "agents",
17995
+ mcpPath: (0, import_path3.join)(workspacePath, ".agents", "mcp.json"),
17996
+ isFallback: true
17997
+ };
17949
17998
  }
17950
- function readMcpConfig(workspacePath) {
17951
- const mcpPath = getMcpConfigPath(workspacePath);
17999
+ function readMcpConfig(mcpPath) {
17952
18000
  if (!(0, import_fs3.existsSync)(mcpPath)) return { servers: {} };
17953
18001
  try {
17954
18002
  return JSON.parse((0, import_fs3.readFileSync)(mcpPath, "utf-8"));
@@ -17956,12 +18004,12 @@ function readMcpConfig(workspacePath) {
17956
18004
  return { servers: {} };
17957
18005
  }
17958
18006
  }
17959
- function writeMcpConfig(workspacePath, config2) {
17960
- const mcpPath = getMcpConfigPath(workspacePath);
18007
+ function writeMcpConfig(mcpPath, config2) {
18008
+ (0, import_fs3.mkdirSync)((0, import_path3.dirname)(mcpPath), { recursive: true });
17961
18009
  (0, import_fs3.writeFileSync)(mcpPath, JSON.stringify(config2, null, 2) + "\n");
17962
18010
  }
17963
- function injectCortexMcpServer(workspacePath, cortexUrl, cortexToken) {
17964
- const config2 = readMcpConfig(workspacePath);
18011
+ function injectCortexMcpServer(mcpPath, cortexUrl, cortexToken) {
18012
+ const config2 = readMcpConfig(mcpPath);
17965
18013
  const existed = "cortex" in config2.servers;
17966
18014
  config2.servers["cortex"] = {
17967
18015
  type: "stdio",
@@ -17972,74 +18020,63 @@ function injectCortexMcpServer(workspacePath, cortexUrl, cortexToken) {
17972
18020
  ...cortexToken ? { CORTEX_API_TOKEN: cortexToken } : {}
17973
18021
  }
17974
18022
  };
17975
- writeMcpConfig(workspacePath, config2);
18023
+ writeMcpConfig(mcpPath, config2);
17976
18024
  return {
17977
18025
  added: !existed,
17978
18026
  updated: existed
17979
18027
  };
17980
18028
  }
17981
- function removeCortexMcpServer(workspacePath) {
17982
- const config2 = readMcpConfig(workspacePath);
18029
+ function removeCortexMcpServer(mcpPath) {
18030
+ const config2 = readMcpConfig(mcpPath);
17983
18031
  if (!("cortex" in config2.servers)) return { removed: false };
17984
18032
  delete config2.servers["cortex"];
17985
- writeMcpConfig(workspacePath, config2);
18033
+ writeMcpConfig(mcpPath, config2);
17986
18034
  return { removed: true };
17987
18035
  }
17988
- function hasCortexMcp(workspacePath) {
17989
- const config2 = readMcpConfig(workspacePath);
18036
+ function hasCortexMcp(mcpPath) {
18037
+ const config2 = readMcpConfig(mcpPath);
17990
18038
  return "cortex" in config2.servers;
17991
18039
  }
17992
18040
  function printMcpStatus(workspacePath) {
17993
- const mcpPath = getMcpConfigPath(workspacePath);
17994
- if (!(0, import_fs3.existsSync)(mcpPath)) {
17995
- console.log(source_default.yellow(" \u26A0 No .vscode/mcp.json found"));
17996
- return;
18041
+ const candidates = [
18042
+ {
18043
+ label: ".vscode/mcp.json",
18044
+ path: (0, import_path3.join)(workspacePath, ".vscode", "mcp.json")
18045
+ },
18046
+ {
18047
+ label: ".cursor/mcp.json",
18048
+ path: (0, import_path3.join)(workspacePath, ".cursor", "mcp.json")
18049
+ },
18050
+ {
18051
+ label: ".claude/mcp.json",
18052
+ path: (0, import_path3.join)(workspacePath, ".claude", "mcp.json")
18053
+ },
18054
+ {
18055
+ label: ".agents/mcp.json",
18056
+ path: (0, import_path3.join)(workspacePath, ".agents", "mcp.json")
18057
+ }
18058
+ ];
18059
+ let found = false;
18060
+ for (const { label, path } of candidates) {
18061
+ if (!(0, import_fs3.existsSync)(path)) continue;
18062
+ const config2 = readMcpConfig(path);
18063
+ if ("cortex" in config2.servers) {
18064
+ const url = config2.servers["cortex"]?.env?.["CORTEX_URL"] ?? "(not set)";
18065
+ console.log(
18066
+ source_default.green(` \u2713 MCP server "cortex" configured in ${label} \u2192 ${url}`)
18067
+ );
18068
+ found = true;
18069
+ }
17997
18070
  }
17998
- const config2 = readMcpConfig(workspacePath);
17999
- if ("cortex" in config2.servers) {
18000
- const entry = config2.servers["cortex"];
18001
- const url = entry.env?.["CORTEX_URL"] ?? "(not set)";
18002
- console.log(source_default.green(` \u2713 MCP server "cortex" configured \u2192 ${url}`));
18003
- } else {
18071
+ if (!found) {
18004
18072
  console.log(
18005
- source_default.yellow(' \u26A0 MCP server "cortex" not found in .vscode/mcp.json')
18073
+ source_default.yellow(' \u26A0 MCP server "cortex" not found in any known config')
18006
18074
  );
18007
18075
  }
18008
18076
  }
18009
18077
  function getCursorMcpPath(workspacePath) {
18010
18078
  return (0, import_path3.join)(workspacePath, ".cursor", "mcp.json");
18011
18079
  }
18012
- function configureCursorMcp(workspacePath, cortexUrl, cortexToken) {
18013
- const cursorDir = (0, import_path3.join)(workspacePath, ".cursor");
18014
- if (!(0, import_fs3.existsSync)(cursorDir)) {
18015
- return {
18016
- configured: false,
18017
- skipped: true,
18018
- reason: ".cursor/ not found (Cursor not configured)"
18019
- };
18020
- }
18021
- const mcpPath = getCursorMcpPath(workspacePath);
18022
- let config2 = { servers: {} };
18023
- if ((0, import_fs3.existsSync)(mcpPath)) {
18024
- try {
18025
- config2 = JSON.parse((0, import_fs3.readFileSync)(mcpPath, "utf-8"));
18026
- } catch {
18027
- config2 = { servers: {} };
18028
- }
18029
- }
18030
- config2.servers["cortex"] = {
18031
- type: "stdio",
18032
- command: "npx",
18033
- args: ["-y", "@cortex-context/cli", "mcp-serve"],
18034
- env: {
18035
- CORTEX_URL: cortexUrl,
18036
- ...cortexToken ? { CORTEX_API_TOKEN: cortexToken } : {}
18037
- }
18038
- };
18039
- (0, import_fs3.mkdirSync)(cursorDir, { recursive: true });
18040
- (0, import_fs3.writeFileSync)(mcpPath, JSON.stringify(config2, null, 2) + "\n");
18041
- return { configured: true, skipped: false };
18042
- }
18043
18080
  function removeCursorMcp(workspacePath) {
18044
18081
  const mcpPath = getCursorMcpPath(workspacePath);
18045
18082
  if (!(0, import_fs3.existsSync)(mcpPath)) return { removed: false };
@@ -18156,7 +18193,6 @@ function writeCortexConfig(workspacePath, force) {
18156
18193
  }
18157
18194
  const templatePath = (0, import_path4.join)(
18158
18195
  __dirname,
18159
- "..",
18160
18196
  "templates",
18161
18197
  "local",
18162
18198
  "cortex.config.template.yaml"
@@ -18173,10 +18209,10 @@ function writeCortexConfig(workspacePath, force) {
18173
18209
  var import_child_process = require("child_process");
18174
18210
  var import_fs5 = require("fs");
18175
18211
  var import_path5 = require("path");
18212
+ var import_os3 = require("os");
18176
18213
  async function deployLocalStack(workspacePath) {
18177
18214
  const templatePath = (0, import_path5.join)(
18178
18215
  __dirname,
18179
- "..",
18180
18216
  "templates",
18181
18217
  "local",
18182
18218
  "docker-compose.local.yml"
@@ -18209,6 +18245,58 @@ function isDockerAvailable() {
18209
18245
  return false;
18210
18246
  }
18211
18247
  }
18248
+ async function installDocker() {
18249
+ const os2 = (0, import_os3.platform)();
18250
+ try {
18251
+ if (os2 === "linux") {
18252
+ console.log(
18253
+ source_default.dim(" \u2192 Running Docker install script (curl | sh)...")
18254
+ );
18255
+ (0, import_child_process.execSync)("curl -fsSL https://get.docker.com | sh", { stdio: "inherit" });
18256
+ const user = process.env["USER"] ?? process.env["LOGNAME"];
18257
+ if (user) {
18258
+ (0, import_child_process.spawnSync)("usermod", ["-aG", "docker", user], { stdio: "inherit" });
18259
+ }
18260
+ return { installed: true };
18261
+ }
18262
+ if (os2 === "darwin") {
18263
+ console.log(source_default.dim(" \u2192 Installing Docker Desktop via Homebrew..."));
18264
+ (0, import_child_process.execSync)("brew install --cask docker", { stdio: "inherit" });
18265
+ return { installed: true };
18266
+ }
18267
+ if (os2 === "win32") {
18268
+ console.log(source_default.dim(" \u2192 Installing Docker Desktop via winget..."));
18269
+ (0, import_child_process.execSync)(
18270
+ "winget install --id Docker.DockerDesktop -e --silent --accept-package-agreements --accept-source-agreements",
18271
+ {
18272
+ stdio: "inherit",
18273
+ shell: "cmd.exe"
18274
+ }
18275
+ );
18276
+ return { installed: true };
18277
+ }
18278
+ return { installed: false, reason: `Unsupported OS: ${os2}` };
18279
+ } catch (err) {
18280
+ return {
18281
+ installed: false,
18282
+ reason: err instanceof Error ? err.message : String(err)
18283
+ };
18284
+ }
18285
+ }
18286
+ async function waitForCortexHealth(cortexUrl, maxWaitMs = 12e4) {
18287
+ const deadline = Date.now() + maxWaitMs;
18288
+ while (Date.now() < deadline) {
18289
+ try {
18290
+ const res = await fetch(`${cortexUrl}/health`, {
18291
+ signal: AbortSignal.timeout(4e3)
18292
+ });
18293
+ if (res.ok) return { healthy: true };
18294
+ } catch {
18295
+ }
18296
+ await new Promise((r) => setTimeout(r, 5e3));
18297
+ }
18298
+ return { healthy: false };
18299
+ }
18212
18300
 
18213
18301
  // src/lib/hooks.ts
18214
18302
  var import_fs6 = require("fs");
@@ -18388,7 +18476,7 @@ async function initCommand(options) {
18388
18476
  cortexToken = "dev-token-local";
18389
18477
  console.log(source_default.dim(" Mode: local Docker stack"));
18390
18478
  } else {
18391
- const responses = await (0, import_prompts.default)(
18479
+ const responses = await (0, import_prompts2.default)(
18392
18480
  [
18393
18481
  {
18394
18482
  type: options.url ? null : "text",
@@ -18518,23 +18606,34 @@ async function initCommand(options) {
18518
18606
  if (!options.skipMcp) {
18519
18607
  console.log("");
18520
18608
  console.log(source_default.bold(" Phase 2: MCP Server"));
18521
- const mcpStatus = injectCortexMcpServer(
18522
- workspacePath,
18523
- cortexUrl,
18524
- cortexToken
18525
- );
18526
- if (mcpStatus.added) {
18527
- console.log(source_default.green(" \u2713 .vscode/mcp.json \u2014 Cortex server added"));
18528
- } else {
18529
- console.log(source_default.cyan(" \u21BB .vscode/mcp.json \u2014 Cortex server updated"));
18530
- }
18531
- const cursorMcp = configureCursorMcp(workspacePath, cortexUrl, cortexToken);
18532
- if (cursorMcp.configured) {
18609
+ const detected = await detectWorkspaceTarget(workspacePath);
18610
+ if (!detected) {
18533
18611
  console.log(
18534
- source_default.green(" \u2713 .cursor/mcp.json \u2014 Cortex server configured")
18612
+ source_default.yellow(" \u26A0 MCP config skipped \u2014 no target directory confirmed")
18535
18613
  );
18536
- } else if (!cursorMcp.skipped) {
18537
- console.log(source_default.yellow(` \u26A0 .cursor/mcp.json \u2014 ${cursorMcp.reason}`));
18614
+ } else {
18615
+ const targetLabel = {
18616
+ vscode: ".vscode/mcp.json",
18617
+ cursor: ".cursor/mcp.json",
18618
+ claude: ".claude/mcp.json",
18619
+ agents: ".agents/mcp.json"
18620
+ };
18621
+ const label = targetLabel[detected.target] ?? detected.mcpPath;
18622
+ if (detected.isFallback) {
18623
+ console.log(
18624
+ source_default.dim(` \u2139 Installing into ${label} (IDE-agnostic standard)`)
18625
+ );
18626
+ }
18627
+ const mcpStatus = injectCortexMcpServer(
18628
+ detected.mcpPath,
18629
+ cortexUrl,
18630
+ cortexToken
18631
+ );
18632
+ if (mcpStatus.added) {
18633
+ console.log(source_default.green(` \u2713 ${label} \u2014 Cortex server added`));
18634
+ } else {
18635
+ console.log(source_default.cyan(` \u21BB ${label} \u2014 Cortex server updated`));
18636
+ }
18538
18637
  }
18539
18638
  const claudeMcp = configureClaudeDesktop(cortexUrl, cortexToken);
18540
18639
  if (claudeMcp.configured) {
@@ -27926,15 +28025,176 @@ async function serveCommand() {
27926
28025
  await runMcpServer();
27927
28026
  }
27928
28027
 
28028
+ // src/commands/server.ts
28029
+ var import_os4 = require("os");
28030
+ var import_prompts3 = __toESM(require_prompts3());
28031
+ var CORTEX_URL2 = "http://localhost:8082";
28032
+ var NEO4J_URL = "http://localhost:7474";
28033
+ async function serverCommand(options) {
28034
+ console.log("");
28035
+ console.log(source_default.bold.cyan(" \u25C6 Cortex Context \u2014 Server"));
28036
+ console.log(
28037
+ source_default.dim(
28038
+ " Installs and starts the Cortex stack (Neo4j + Cortex API) via Docker."
28039
+ )
28040
+ );
28041
+ console.log("");
28042
+ const workDir = options.dir ?? process.cwd();
28043
+ console.log(source_default.bold(" Step 1: Docker"));
28044
+ const dockerReady = isDockerAvailable();
28045
+ if (dockerReady) {
28046
+ console.log(source_default.green(" \u2713 Docker is available"));
28047
+ } else {
28048
+ console.log(source_default.yellow(" \u26A0 Docker not found on PATH"));
28049
+ if (options.skipDockerInstall) {
28050
+ console.error(
28051
+ source_default.red(
28052
+ " \u2717 --skip-docker-install set but Docker is required. Install Docker manually and retry."
28053
+ )
28054
+ );
28055
+ process.exit(1);
28056
+ }
28057
+ const os2 = (0, import_os4.platform)();
28058
+ const installMethod = {
28059
+ linux: "curl | sh (official script, may require sudo)",
28060
+ darwin: "Homebrew (brew install --cask docker)",
28061
+ win32: "winget (winget install Docker.DockerDesktop)"
28062
+ };
28063
+ const method = installMethod[os2] ?? `unsupported OS (${os2})`;
28064
+ if (!installMethod[os2]) {
28065
+ console.error(
28066
+ source_default.red(` \u2717 Automatic Docker install is not supported on ${os2}.`)
28067
+ );
28068
+ console.error(
28069
+ source_default.dim(
28070
+ " Install Docker manually: https://docs.docker.com/get-docker/"
28071
+ )
28072
+ );
28073
+ process.exit(1);
28074
+ }
28075
+ console.log("");
28076
+ console.log(source_default.dim(` Install method: ${method}`));
28077
+ console.log(source_default.dim(" This will install Docker on your machine."));
28078
+ console.log("");
28079
+ const { confirm } = await (0, import_prompts3.default)({
28080
+ type: "confirm",
28081
+ name: "confirm",
28082
+ message: "Install Docker now?",
28083
+ initial: true
28084
+ });
28085
+ if (!confirm) {
28086
+ console.log(
28087
+ source_default.yellow("\n Aborted. Install Docker manually and run again.")
28088
+ );
28089
+ process.exit(0);
28090
+ }
28091
+ console.log("");
28092
+ const spinner = ora(" Installing Docker...").start();
28093
+ const result = await installDocker();
28094
+ if (!result.installed) {
28095
+ spinner.fail(source_default.red(` \u2717 Docker install failed: ${result.reason}`));
28096
+ console.log(
28097
+ source_default.dim(
28098
+ " Install Docker manually: https://docs.docker.com/get-docker/"
28099
+ )
28100
+ );
28101
+ process.exit(1);
28102
+ }
28103
+ spinner.succeed(source_default.green(" \u2713 Docker installed"));
28104
+ if (os2 === "win32") {
28105
+ console.log(
28106
+ source_default.yellow(
28107
+ " \u26A0 Docker Desktop was installed. Please start it manually, then re-run this command."
28108
+ )
28109
+ );
28110
+ process.exit(0);
28111
+ }
28112
+ if (os2 === "linux") {
28113
+ console.log(
28114
+ source_default.dim(
28115
+ " \u2139 You may need to log out and back in for the docker group to take effect."
28116
+ )
28117
+ );
28118
+ }
28119
+ console.log("");
28120
+ }
28121
+ console.log("");
28122
+ console.log(source_default.bold(" Step 2: Containers to start"));
28123
+ console.log(source_default.dim(" \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
28124
+ console.log(source_default.dim(" \u2502 neo4j \u2192 localhost:7474 (UI: 7474) \u2502"));
28125
+ console.log(source_default.dim(" \u2502 cortex-api \u2192 localhost:8082 \u2502"));
28126
+ console.log(source_default.dim(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
28127
+ console.log("");
28128
+ console.log(source_default.dim(` Working directory: ${workDir}`));
28129
+ console.log("");
28130
+ const { proceed } = await (0, import_prompts3.default)({
28131
+ type: "confirm",
28132
+ name: "proceed",
28133
+ message: "Start the Cortex stack now?",
28134
+ initial: true
28135
+ });
28136
+ if (!proceed) {
28137
+ console.log(source_default.yellow("\n Aborted."));
28138
+ process.exit(0);
28139
+ }
28140
+ console.log("");
28141
+ console.log(source_default.bold(" Step 3: Starting Cortex stack"));
28142
+ const startSpinner = ora(" Running docker compose up -d...").start();
28143
+ const startResult = await deployLocalStack(workDir);
28144
+ if (!startResult.started) {
28145
+ startSpinner.fail(
28146
+ source_default.red(` \u2717 Docker Compose failed: ${startResult.error}`)
28147
+ );
28148
+ process.exit(1);
28149
+ }
28150
+ startSpinner.succeed(source_default.green(" \u2713 Containers started"));
28151
+ console.log("");
28152
+ console.log(source_default.bold(" Step 4: Waiting for Cortex API..."));
28153
+ const healthSpinner = ora(
28154
+ " Polling http://localhost:8082/health (up to 2 min)..."
28155
+ ).start();
28156
+ const { healthy } = await waitForCortexHealth(CORTEX_URL2);
28157
+ if (!healthy) {
28158
+ healthSpinner.warn(
28159
+ source_default.yellow(
28160
+ " \u26A0 Cortex API did not respond in time \u2014 containers may still be starting."
28161
+ )
28162
+ );
28163
+ console.log(source_default.dim(` Check manually: curl ${CORTEX_URL2}/health`));
28164
+ console.log(
28165
+ source_default.dim(" Or: docker compose -f docker-compose.local.yml logs")
28166
+ );
28167
+ } else {
28168
+ healthSpinner.succeed(source_default.green(" \u2713 Cortex API is healthy"));
28169
+ }
28170
+ console.log("");
28171
+ console.log(source_default.bold.green(" \u2705 Cortex stack is running!"));
28172
+ console.log("");
28173
+ console.log(source_default.bold(" Services:"));
28174
+ console.log(source_default.cyan(` Cortex API \u2192 ${CORTEX_URL2}`));
28175
+ console.log(source_default.cyan(` Neo4j UI \u2192 ${NEO4J_URL}`));
28176
+ console.log(source_default.dim(" Neo4j login \u2192 neo4j / cortex-local"));
28177
+ console.log("");
28178
+ console.log(source_default.bold(" Next steps:"));
28179
+ console.log(source_default.dim(" 1. Initialize your workspace:"));
28180
+ console.log(source_default.cyan(` cortex-context init --url ${CORTEX_URL2}`));
28181
+ console.log(source_default.dim(" 2. Check connectivity:"));
28182
+ console.log(source_default.cyan(" cortex-context doctor"));
28183
+ console.log("");
28184
+ console.log(source_default.dim(" To stop the stack:"));
28185
+ console.log(source_default.dim(" docker compose -f docker-compose.local.yml down"));
28186
+ console.log("");
28187
+ }
28188
+
27929
28189
  // src/commands/uninstall.ts
27930
28190
  var import_path13 = require("path");
27931
28191
  var import_fs12 = require("fs");
27932
- var import_prompts2 = __toESM(require_prompts3());
28192
+ var import_prompts4 = __toESM(require_prompts3());
27933
28193
  var CORTEX_SKILLS = [
27934
28194
  "cortex-research",
27935
28195
  "cortex-dimensions",
27936
28196
  "cortex-ingest",
27937
- "generate-spec"
28197
+ "cortex-generate-spec"
27938
28198
  ];
27939
28199
  async function uninstallCommand(options) {
27940
28200
  console.log("");
@@ -27950,7 +28210,9 @@ async function uninstallCommand(options) {
27950
28210
  );
27951
28211
  const hasMcp = (0, import_fs12.existsSync)((0, import_path13.join)(workspacePath, ".vscode", "mcp.json"));
27952
28212
  const hasCursorMcp = (0, import_fs12.existsSync)((0, import_path13.join)(workspacePath, ".cursor", "mcp.json"));
27953
- const hasHook = (0, import_fs12.existsSync)((0, import_path13.join)(workspacePath, ".git", "hooks", "post-commit"));
28213
+ const hasHook = (0, import_fs12.existsSync)(
28214
+ (0, import_path13.join)(workspacePath, ".git", "hooks", "post-commit")
28215
+ );
27954
28216
  const hasConfig = (0, import_fs12.existsSync)(
27955
28217
  (0, import_path13.join)(process.env["HOME"] ?? "~", ".cortex-context", "config.json")
27956
28218
  );
@@ -27967,7 +28229,9 @@ async function uninstallCommand(options) {
27967
28229
  }
27968
28230
  }
27969
28231
  if (!options.keepHook && hasHook) {
27970
- console.log(source_default.dim(" \xB7 .git/hooks/post-commit (cortex auto-sync hook)"));
28232
+ console.log(
28233
+ source_default.dim(" \xB7 .git/hooks/post-commit (cortex auto-sync hook)")
28234
+ );
27971
28235
  }
27972
28236
  if (!options.keepConfig && hasConfig) {
27973
28237
  console.log(source_default.dim(" \xB7 ~/.cortex-context/config.json"));
@@ -27980,7 +28244,7 @@ async function uninstallCommand(options) {
27980
28244
  }
27981
28245
  console.log("");
27982
28246
  if (!options.yes) {
27983
- const { confirmed } = await (0, import_prompts2.default)({
28247
+ const { confirmed } = await (0, import_prompts4.default)({
27984
28248
  type: "confirm",
27985
28249
  name: "confirmed",
27986
28250
  message: "Proceed with uninstall?",
@@ -27999,13 +28263,21 @@ async function uninstallCommand(options) {
27999
28263
  try {
28000
28264
  const result = removeCortexMcpServer(workspacePath);
28001
28265
  if (result.removed) {
28002
- console.log(source_default.green(' \u2713 .vscode/mcp.json \u2014 "cortex" entry removed'));
28266
+ console.log(
28267
+ source_default.green(' \u2713 .vscode/mcp.json \u2014 "cortex" entry removed')
28268
+ );
28003
28269
  removed++;
28004
28270
  } else {
28005
- console.log(source_default.dim(' \xB7 .vscode/mcp.json \u2014 no "cortex" entry found'));
28271
+ console.log(
28272
+ source_default.dim(' \xB7 .vscode/mcp.json \u2014 no "cortex" entry found')
28273
+ );
28006
28274
  }
28007
28275
  } catch (err) {
28008
- console.log(source_default.red(` \u2717 .vscode/mcp.json \u2014 ${err instanceof Error ? err.message : err}`));
28276
+ console.log(
28277
+ source_default.red(
28278
+ ` \u2717 .vscode/mcp.json \u2014 ${err instanceof Error ? err.message : err}`
28279
+ )
28280
+ );
28009
28281
  errors++;
28010
28282
  }
28011
28283
  }
@@ -28013,18 +28285,28 @@ async function uninstallCommand(options) {
28013
28285
  try {
28014
28286
  const result = removeCursorMcp(workspacePath);
28015
28287
  if (result.removed) {
28016
- console.log(source_default.green(' \u2713 .cursor/mcp.json \u2014 "cortex" entry removed'));
28288
+ console.log(
28289
+ source_default.green(' \u2713 .cursor/mcp.json \u2014 "cortex" entry removed')
28290
+ );
28017
28291
  removed++;
28018
28292
  }
28019
28293
  } catch (err) {
28020
- console.log(source_default.red(` \u2717 .cursor/mcp.json \u2014 ${err instanceof Error ? err.message : err}`));
28294
+ console.log(
28295
+ source_default.red(
28296
+ ` \u2717 .cursor/mcp.json \u2014 ${err instanceof Error ? err.message : err}`
28297
+ )
28298
+ );
28021
28299
  errors++;
28022
28300
  }
28023
28301
  }
28024
28302
  try {
28025
28303
  const result = removeClaudeDesktopMcp();
28026
28304
  if (result.removed) {
28027
- console.log(source_default.green(` \u2713 Claude Desktop \u2014 "cortex" entry removed (${result.path})`));
28305
+ console.log(
28306
+ source_default.green(
28307
+ ` \u2713 Claude Desktop \u2014 "cortex" entry removed (${result.path})`
28308
+ )
28309
+ );
28028
28310
  removed++;
28029
28311
  }
28030
28312
  } catch {
@@ -28037,7 +28319,11 @@ async function uninstallCommand(options) {
28037
28319
  console.log(source_default.green(` \u2713 .github/skills/${skill}/ \u2014 removed`));
28038
28320
  removed++;
28039
28321
  } catch (err) {
28040
- console.log(source_default.red(` \u2717 .github/skills/${skill}/ \u2014 ${err instanceof Error ? err.message : err}`));
28322
+ console.log(
28323
+ source_default.red(
28324
+ ` \u2717 .github/skills/${skill}/ \u2014 ${err instanceof Error ? err.message : err}`
28325
+ )
28326
+ );
28041
28327
  errors++;
28042
28328
  }
28043
28329
  }
@@ -28052,7 +28338,9 @@ async function uninstallCommand(options) {
28052
28338
  console.log(source_default.green(" \u2713 .git/hooks/post-commit \u2014 removed"));
28053
28339
  removed++;
28054
28340
  } else {
28055
- console.log(source_default.dim(" \xB7 .git/hooks/post-commit \u2014 not ours, skipped"));
28341
+ console.log(
28342
+ source_default.dim(" \xB7 .git/hooks/post-commit \u2014 not ours, skipped")
28343
+ );
28056
28344
  }
28057
28345
  } catch {
28058
28346
  }
@@ -28063,17 +28351,33 @@ async function uninstallCommand(options) {
28063
28351
  console.log(source_default.green(" \u2713 ~/.cortex-context/config.json \u2014 removed"));
28064
28352
  removed++;
28065
28353
  } catch (err) {
28066
- console.log(source_default.red(` \u2717 ~/.cortex-context/config.json \u2014 ${err instanceof Error ? err.message : err}`));
28354
+ console.log(
28355
+ source_default.red(
28356
+ ` \u2717 ~/.cortex-context/config.json \u2014 ${err instanceof Error ? err.message : err}`
28357
+ )
28358
+ );
28067
28359
  errors++;
28068
28360
  }
28069
28361
  }
28070
28362
  console.log("");
28071
28363
  if (errors === 0) {
28072
- console.log(source_default.bold.green(` \u2705 Uninstall complete (${removed} item${removed !== 1 ? "s" : ""} removed)`));
28364
+ console.log(
28365
+ source_default.bold.green(
28366
+ ` \u2705 Uninstall complete (${removed} item${removed !== 1 ? "s" : ""} removed)`
28367
+ )
28368
+ );
28073
28369
  console.log("");
28074
- console.log(source_default.dim(' Reload VS Code (Cmd/Ctrl+Shift+P \u2192 "Reload Window") to deactivate the MCP server.'));
28370
+ console.log(
28371
+ source_default.dim(
28372
+ ' Reload VS Code (Cmd/Ctrl+Shift+P \u2192 "Reload Window") to deactivate the MCP server.'
28373
+ )
28374
+ );
28075
28375
  } else {
28076
- console.log(source_default.bold.yellow(` \u26A0 Uninstall finished with ${errors} error${errors !== 1 ? "s" : ""}`));
28376
+ console.log(
28377
+ source_default.bold.yellow(
28378
+ ` \u26A0 Uninstall finished with ${errors} error${errors !== 1 ? "s" : ""}`
28379
+ )
28380
+ );
28077
28381
  }
28078
28382
  console.log("");
28079
28383
  }
@@ -28101,6 +28405,15 @@ function createCli() {
28101
28405
  "--local",
28102
28406
  "Deploy a local Cortex stack with Docker (mutually exclusive with --url)"
28103
28407
  ).option("--skip-mcp", "Skip MCP server configuration").option("--skip-skills", "Skip Skills installation").option("--skip-hooks", "Skip git hook installation").option("--skip-rules", "Skip Copilot/Cursor rules injection").option("--force", "Overwrite existing files without prompting").action(initCommand);
28408
+ program3.command("server").description(
28409
+ "Install Docker (if needed) and start the Cortex stack (Neo4j + Cortex API) locally"
28410
+ ).option(
28411
+ "--dir <path>",
28412
+ "Directory to place docker-compose.local.yml (defaults to current directory)"
28413
+ ).option(
28414
+ "--skip-docker-install",
28415
+ "Fail instead of auto-installing Docker when it is not found"
28416
+ ).action(serverCommand);
28104
28417
  program3.command("sync").description("Ingest latest git diff into the Cortex Knowledge Graph").option("--repo <path>", "Repository path (defaults to current directory)").option("--dry-run", "Show diff without sending to Cortex API").action(syncCommand);
28105
28418
  program3.command("update").description(
28106
28419
  "Update Skills and MCP Server files to the latest bundled version"