@cortex-context/cli 0.0.12 → 0.0.13

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 prompts6 = require_prompts();
5620
+ var prompts7 = 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 (prompts6[type] === void 0) {
5671
+ if (prompts7[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 prompts6[type](question);
5682
+ answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : yield prompts7[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: prompts6,
5714
+ prompts: prompts7,
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 prompts6 = require_prompts2();
7801
+ var prompts7 = 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 (prompts6[type] === void 0) {
7833
+ if (prompts7[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 prompts6[type](question);
7844
+ answer = prompt._injected ? getInjectedAnswer(prompt._injected, question.initial) : await prompts7[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: prompts6, inject, override });
7867
+ module2.exports = Object.assign(prompt, { prompt, prompts: prompts7, inject, override });
7868
7868
  }
7869
7869
  });
7870
7870
 
@@ -18008,16 +18008,33 @@ function writeMcpConfig(mcpPath, config2) {
18008
18008
  (0, import_fs3.mkdirSync)((0, import_path3.dirname)(mcpPath), { recursive: true });
18009
18009
  (0, import_fs3.writeFileSync)(mcpPath, JSON.stringify(config2, null, 2) + "\n");
18010
18010
  }
18011
- function injectCortexMcpServer(mcpPath, cortexUrl, cortexToken) {
18011
+ function injectCortexMcpServer(mcpPath, cortexUrl, cortexToken, target) {
18012
18012
  const config2 = readMcpConfig(mcpPath);
18013
18013
  const existed = "cortex" in config2.servers;
18014
+ let cortexTokenEnv;
18015
+ if (cortexToken) {
18016
+ if (target === "vscode" || target === "claude") {
18017
+ if (!config2.inputs) config2.inputs = [];
18018
+ if (!config2.inputs.some((i) => i.id === "cortex_token")) {
18019
+ config2.inputs.push({
18020
+ id: "cortex_token",
18021
+ type: "promptString",
18022
+ description: "Cortex API Token (set during cortex-context server setup)",
18023
+ password: true
18024
+ });
18025
+ }
18026
+ cortexTokenEnv = "${input:cortex_token}";
18027
+ } else {
18028
+ cortexTokenEnv = "${env:CORTEX_API_TOKEN}";
18029
+ }
18030
+ }
18014
18031
  config2.servers["cortex"] = {
18015
18032
  type: "stdio",
18016
18033
  command: "npx",
18017
18034
  args: ["-y", "@cortex-context/cli", "mcp-serve"],
18018
18035
  env: {
18019
18036
  CORTEX_URL: cortexUrl,
18020
- ...cortexToken ? { CORTEX_API_TOKEN: cortexToken } : {}
18037
+ ...cortexTokenEnv ? { CORTEX_API_TOKEN: cortexTokenEnv } : {}
18021
18038
  }
18022
18039
  };
18023
18040
  writeMcpConfig(mcpPath, config2);
@@ -18133,7 +18150,7 @@ function configureClaudeDesktop(cortexUrl, cortexToken) {
18133
18150
  args: ["-y", "@cortex-context/cli", "mcp-serve"],
18134
18151
  env: {
18135
18152
  CORTEX_URL: cortexUrl,
18136
- ...cortexToken ? { CORTEX_API_TOKEN: cortexToken } : {}
18153
+ ...cortexToken ? { CORTEX_API_TOKEN: "${env:CORTEX_API_TOKEN}" } : {}
18137
18154
  }
18138
18155
  };
18139
18156
  (0, import_fs3.writeFileSync)(configPath, JSON.stringify(config2, null, 2) + "\n");
@@ -18295,6 +18312,10 @@ async function deployLocalStack(workspacePath, opts = {}) {
18295
18312
  if (!(0, import_fs5.existsSync)(destPath)) {
18296
18313
  (0, import_fs5.cpSync)(templatePath, destPath);
18297
18314
  }
18315
+ const envPath = (0, import_path5.join)(workspacePath, ".env");
18316
+ const envContent = `CORTEX_API_TOKEN=${opts.token ?? ""}
18317
+ `;
18318
+ (0, import_fs5.writeFileSync)(envPath, envContent, { encoding: "utf-8" });
18298
18319
  const imageTag = opts.embeddings ? "latest-embeddings" : "latest";
18299
18320
  const cortexImage = `ghcr.io/rodrigoroldan/cortex-context:${imageTag}`;
18300
18321
  try {
@@ -18711,7 +18732,8 @@ async function initCommand(options) {
18711
18732
  const mcpStatus = injectCortexMcpServer(
18712
18733
  detected.mcpPath,
18713
18734
  cortexUrl,
18714
- cortexToken
18735
+ cortexToken,
18736
+ detected.target
18715
18737
  );
18716
18738
  if (mcpStatus.added) {
18717
18739
  console.log(source_default.green(` \u2713 ${label} \u2014 Cortex server added`));
@@ -28113,6 +28135,7 @@ async function serveCommand() {
28113
28135
  var import_os4 = require("os");
28114
28136
  var import_fs12 = require("fs");
28115
28137
  var import_path13 = require("path");
28138
+ var import_crypto = require("crypto");
28116
28139
  var import_prompts3 = __toESM(require_prompts3());
28117
28140
  var CORTEX_URL2 = "http://localhost:8082";
28118
28141
  var NEO4J_URL = "http://localhost:7474";
@@ -28233,7 +28256,73 @@ async function serverCommand(options) {
28233
28256
  process.exit(0);
28234
28257
  }
28235
28258
  console.log("");
28236
- console.log(source_default.bold(" Step 3: Starting Cortex stack"));
28259
+ console.log(source_default.bold(" Step 3: API Token"));
28260
+ console.log(
28261
+ source_default.dim(" Optionally secure write endpoints with a Bearer token.")
28262
+ );
28263
+ console.log(
28264
+ source_default.dim(" Leave open (no token) for purely local/private use.")
28265
+ );
28266
+ console.log("");
28267
+ const generatedToken = (0, import_crypto.randomBytes)(24).toString("hex");
28268
+ const { tokenChoice } = await (0, import_prompts3.default)(
28269
+ {
28270
+ type: "select",
28271
+ name: "tokenChoice",
28272
+ message: "API token:",
28273
+ choices: [
28274
+ {
28275
+ title: "Generate random token " + source_default.dim("(recommended)"),
28276
+ value: "generate"
28277
+ },
28278
+ { title: "Enter my own token", value: "custom" },
28279
+ {
28280
+ title: "No token " + source_default.dim("(open access \u2014 local only)"),
28281
+ value: "none"
28282
+ }
28283
+ ],
28284
+ initial: 0
28285
+ },
28286
+ {
28287
+ onCancel: () => {
28288
+ console.log(source_default.yellow("\n Aborted."));
28289
+ process.exit(0);
28290
+ }
28291
+ }
28292
+ );
28293
+ let serverToken = "";
28294
+ if (!tokenChoice || tokenChoice === "none") {
28295
+ console.log(
28296
+ source_default.dim(" \u2139 No token \u2014 API is open (suitable for local use only)")
28297
+ );
28298
+ } else if (tokenChoice === "generate") {
28299
+ serverToken = generatedToken;
28300
+ console.log(source_default.green(" \u2713 Random token generated"));
28301
+ } else {
28302
+ const { customToken } = await (0, import_prompts3.default)(
28303
+ {
28304
+ type: "password",
28305
+ name: "customToken",
28306
+ message: "Enter your token:",
28307
+ validate: (v) => v.trim().length >= 8 || "Token must be at least 8 characters"
28308
+ },
28309
+ {
28310
+ onCancel: () => {
28311
+ console.log(source_default.yellow("\n Aborted."));
28312
+ process.exit(0);
28313
+ }
28314
+ }
28315
+ );
28316
+ serverToken = customToken?.trim() ?? "";
28317
+ if (!serverToken) {
28318
+ console.log(source_default.dim(" \u2139 Empty \u2014 API is open"));
28319
+ } else {
28320
+ console.log(source_default.green(" \u2713 Token saved"));
28321
+ }
28322
+ }
28323
+ writeConfig({ url: CORTEX_URL2, token: serverToken });
28324
+ console.log("");
28325
+ console.log(source_default.bold(" Step 4: Starting Cortex stack"));
28237
28326
  const sysctlFix = tryFixLxcSysctl();
28238
28327
  if (sysctlFix.applied) {
28239
28328
  console.log(
@@ -28257,7 +28346,8 @@ async function serverCommand(options) {
28257
28346
  console.log(source_default.dim(" $ docker compose up -d"));
28258
28347
  console.log("");
28259
28348
  const startResult = await deployLocalStack(workDir, {
28260
- embeddings: options.embeddings ?? false
28349
+ embeddings: options.embeddings ?? false,
28350
+ token: serverToken
28261
28351
  });
28262
28352
  console.log("");
28263
28353
  if (!startResult.started) {
@@ -28306,7 +28396,7 @@ async function serverCommand(options) {
28306
28396
  }
28307
28397
  console.log(source_default.green(" \u2713 Containers started"));
28308
28398
  console.log("");
28309
- console.log(source_default.bold(" Step 4: Waiting for Cortex API..."));
28399
+ console.log(source_default.bold(" Step 5: Waiting for Cortex API..."));
28310
28400
  const healthSpinner = ora(
28311
28401
  " Polling http://localhost:8082/health (up to 2 min)..."
28312
28402
  ).start();
@@ -28332,9 +28422,22 @@ async function serverCommand(options) {
28332
28422
  console.log(source_default.cyan(` Neo4j UI \u2192 ${NEO4J_URL}`));
28333
28423
  console.log(source_default.dim(" Neo4j login \u2192 neo4j / cortex-local"));
28334
28424
  console.log("");
28335
- console.log(source_default.bold(" Next steps:"));
28336
- console.log(source_default.dim(" 1. Initialize your workspace:"));
28337
- console.log(source_default.cyan(` cortex-context init --url ${CORTEX_URL2}`));
28425
+ if (serverToken) {
28426
+ console.log(source_default.bold(" \u{1F511} API Token (save this!):"));
28427
+ console.log(source_default.bold.yellow(` ${serverToken}`));
28428
+ console.log("");
28429
+ console.log(source_default.bold(" Next steps:"));
28430
+ console.log(source_default.dim(" 1. Initialize your workspace:"));
28431
+ console.log(
28432
+ source_default.cyan(
28433
+ ` cortex-context init --url ${CORTEX_URL2} --token ${serverToken}`
28434
+ )
28435
+ );
28436
+ } else {
28437
+ console.log(source_default.bold(" Next steps:"));
28438
+ console.log(source_default.dim(" 1. Initialize your workspace:"));
28439
+ console.log(source_default.cyan(` cortex-context init --url ${CORTEX_URL2}`));
28440
+ }
28338
28441
  console.log(source_default.dim(" 2. Check connectivity:"));
28339
28442
  console.log(source_default.cyan(" cortex-context doctor"));
28340
28443
  console.log("");
@@ -28488,8 +28591,8 @@ async function uninstallCommand(options) {
28488
28591
  if (!options.keepHook && hasHook) {
28489
28592
  const hookPath = (0, import_path14.join)(workspacePath, ".git", "hooks", "post-commit");
28490
28593
  try {
28491
- const { readFileSync: readFileSync8 } = await import("fs");
28492
- const hookContent = readFileSync8(hookPath, "utf-8");
28594
+ const { readFileSync: readFileSync9 } = await import("fs");
28595
+ const hookContent = readFileSync9(hookPath, "utf-8");
28493
28596
  if (hookContent.includes("cortex-context")) {
28494
28597
  (0, import_fs13.unlinkSync)(hookPath);
28495
28598
  console.log(source_default.green(" \u2713 .git/hooks/post-commit \u2014 removed"));
@@ -28556,7 +28659,11 @@ async function resetCommand(options) {
28556
28659
  console.log("");
28557
28660
  console.log(source_default.bold(" \u25C6 Cortex Context \u2014 Reset Graph"));
28558
28661
  console.log("");
28559
- console.log(source_default.yellow(" \u26A0 This will delete ALL nodes and relationships from the graph."));
28662
+ console.log(
28663
+ source_default.yellow(
28664
+ " \u26A0 This will delete ALL nodes and relationships from the graph."
28665
+ )
28666
+ );
28560
28667
  console.log(source_default.dim(` Server: ${url}`));
28561
28668
  console.log("");
28562
28669
  const confirmed = options.yes || await (0, import_prompts5.default)({
@@ -28584,7 +28691,9 @@ async function resetCommand(options) {
28584
28691
  } catch (err) {
28585
28692
  process.stdout.write("\n");
28586
28693
  console.error(
28587
- source_default.red(` \u2717 Network error: ${err instanceof Error ? err.message : String(err)}`)
28694
+ source_default.red(
28695
+ ` \u2717 Network error: ${err instanceof Error ? err.message : String(err)}`
28696
+ )
28588
28697
  );
28589
28698
  process.exit(1);
28590
28699
  }
@@ -28603,11 +28712,133 @@ async function resetCommand(options) {
28603
28712
  console.log(source_default.dim(" Run `cortex-context sync` to re-ingest the graph."));
28604
28713
  }
28605
28714
 
28606
- // src/cli.ts
28715
+ // src/commands/token.ts
28716
+ var import_crypto2 = require("crypto");
28607
28717
  var import_fs14 = require("fs");
28608
28718
  var import_path15 = require("path");
28719
+ var import_os5 = require("os");
28720
+ var import_prompts6 = __toESM(require_prompts3());
28721
+ var CORTEX_DIR = (0, import_path15.join)((0, import_os5.homedir)(), ".cortex-context");
28722
+ var ENV_FILE = (0, import_path15.join)(CORTEX_DIR, ".env");
28723
+ function readEnvToken() {
28724
+ if (!(0, import_fs14.existsSync)(ENV_FILE)) return "";
28725
+ const content = (0, import_fs14.readFileSync)(ENV_FILE, "utf-8");
28726
+ const match = content.match(/^CORTEX_API_TOKEN=(.*)$/m);
28727
+ return match?.[1]?.trim() ?? "";
28728
+ }
28729
+ function writeEnvToken(token) {
28730
+ (0, import_fs14.mkdirSync)(CORTEX_DIR, { recursive: true });
28731
+ if (!(0, import_fs14.existsSync)(ENV_FILE)) {
28732
+ (0, import_fs14.writeFileSync)(ENV_FILE, `CORTEX_API_TOKEN=${token}
28733
+ `, "utf-8");
28734
+ return;
28735
+ }
28736
+ const content = (0, import_fs14.readFileSync)(ENV_FILE, "utf-8");
28737
+ const updated = content.includes("CORTEX_API_TOKEN=") ? content.replace(/^CORTEX_API_TOKEN=.*$/m, `CORTEX_API_TOKEN=${token}`) : content + `CORTEX_API_TOKEN=${token}
28738
+ `;
28739
+ (0, import_fs14.writeFileSync)(ENV_FILE, updated, "utf-8");
28740
+ }
28741
+ async function tokenCommand(options) {
28742
+ console.log("");
28743
+ console.log(source_default.bold(" \u25C6 Cortex Context \u2014 API Token"));
28744
+ console.log("");
28745
+ if (options.set !== void 0) {
28746
+ const newToken = options.set.trim();
28747
+ if (!newToken) {
28748
+ console.log(
28749
+ source_default.yellow(
28750
+ " Clearing token \u2014 API will accept all requests (open access)."
28751
+ )
28752
+ );
28753
+ }
28754
+ writeConfig({ token: newToken });
28755
+ writeEnvToken(newToken);
28756
+ console.log(
28757
+ source_default.green(newToken ? " \u2713 Token updated" : " \u2713 Token cleared")
28758
+ );
28759
+ if (newToken) {
28760
+ console.log("");
28761
+ console.log(source_default.dim(" Restart the Cortex container to apply:"));
28762
+ console.log(
28763
+ source_default.cyan(
28764
+ " docker compose -f ~/.cortex-context/docker-compose.local.yml restart cortex-api"
28765
+ )
28766
+ );
28767
+ }
28768
+ console.log("");
28769
+ return;
28770
+ }
28771
+ if (options.rotate) {
28772
+ const { confirm } = await (0, import_prompts6.default)(
28773
+ {
28774
+ type: "confirm",
28775
+ name: "confirm",
28776
+ message: "Generate a new random token? (requires container restart to apply)",
28777
+ initial: true
28778
+ },
28779
+ {
28780
+ onCancel: () => {
28781
+ console.log(source_default.yellow("\n Aborted."));
28782
+ process.exit(0);
28783
+ }
28784
+ }
28785
+ );
28786
+ if (!confirm) {
28787
+ console.log(source_default.dim(" Aborted."));
28788
+ console.log("");
28789
+ return;
28790
+ }
28791
+ const newToken = (0, import_crypto2.randomBytes)(24).toString("hex");
28792
+ writeConfig({ token: newToken });
28793
+ writeEnvToken(newToken);
28794
+ console.log(source_default.green(" \u2713 New token generated and saved"));
28795
+ console.log("");
28796
+ console.log(source_default.bold(" \u{1F511} New Token:"));
28797
+ console.log(source_default.bold.yellow(` ${newToken}`));
28798
+ console.log("");
28799
+ const config3 = readConfig();
28800
+ console.log(
28801
+ source_default.dim(" Re-initialize your workspace to update MCP config:")
28802
+ );
28803
+ console.log(
28804
+ source_default.cyan(
28805
+ ` cortex-context init --url ${config3.url ?? "http://localhost:8082"} --token ${newToken}`
28806
+ )
28807
+ );
28808
+ console.log(source_default.dim(" Restart the Cortex container:"));
28809
+ console.log(
28810
+ source_default.cyan(
28811
+ " docker compose -f ~/.cortex-context/docker-compose.local.yml restart cortex-api"
28812
+ )
28813
+ );
28814
+ console.log("");
28815
+ return;
28816
+ }
28817
+ const config2 = readConfig();
28818
+ const currentToken = config2.token ?? readEnvToken();
28819
+ if (!currentToken) {
28820
+ console.log(
28821
+ source_default.yellow(" \u26A0 No token configured \u2014 API is in open access mode")
28822
+ );
28823
+ console.log(source_default.dim(" Generate one: cortex-context token --rotate"));
28824
+ console.log(
28825
+ source_default.dim(" Set one: cortex-context token --set <value>")
28826
+ );
28827
+ } else if (options.show) {
28828
+ console.log(source_default.bold(` Token: ${source_default.yellow(currentToken)}`));
28829
+ } else {
28830
+ const masked = currentToken.length > 8 ? currentToken.slice(0, 4) + "\u2022".repeat(currentToken.length - 8) + currentToken.slice(-4) : "\u2022".repeat(currentToken.length);
28831
+ console.log(source_default.dim(` Token: ${masked}`));
28832
+ console.log(source_default.dim(" Use --show to reveal the full token"));
28833
+ }
28834
+ console.log("");
28835
+ }
28836
+
28837
+ // src/cli.ts
28838
+ var import_fs15 = require("fs");
28839
+ var import_path16 = require("path");
28609
28840
  var pkg = JSON.parse(
28610
- (0, import_fs14.readFileSync)((0, import_path15.join)(__dirname, "..", "package.json"), "utf-8")
28841
+ (0, import_fs15.readFileSync)((0, import_path16.join)(__dirname, "..", "package.json"), "utf-8")
28611
28842
  );
28612
28843
  function createCli() {
28613
28844
  const program3 = new Command();
@@ -28655,6 +28886,12 @@ function createCli() {
28655
28886
  program3.command("reset").description(
28656
28887
  "Wipe all nodes and relationships from the Cortex Knowledge Graph (irreversible)"
28657
28888
  ).option("-y, --yes", "Skip confirmation prompt").action(resetCommand);
28889
+ program3.command("token").description(
28890
+ "Show or manage the Cortex API token for the local stack (~/.cortex-context/.env)"
28891
+ ).option("--show", "Reveal the full token (default shows masked)").option("--rotate", "Generate a new random token and save it").option(
28892
+ "--set <value>",
28893
+ "Set a specific token value (empty string clears auth)"
28894
+ ).action(tokenCommand);
28658
28895
  return program3;
28659
28896
  }
28660
28897